Mencetak alamat memori variabel dengan cepat

166

Apakah ada cara untuk mensimulasikan [NSString stringWithFormat:@"%p", myVar], dari Objective-C, dalam bahasa Swift yang baru?

Sebagai contoh:

let str = "A String"
println(" str value \(str) has address: ?")
apouche
sumber
2
In [NSString stringWithFormat:@"%p", myVar], myVarharus berupa pointer. Dalam kode Swift Anda, strbukan penunjuk. Jadi perbandingannya tidak berlaku.
user102008
5
Perlu dicatat bahwa, setidaknya ketika saya mengetik ini, dua komentar di atas salah.
Ben Leggiero

Jawaban:

112

Cepat 2

Ini sekarang merupakan bagian dari perpustakaan standar: unsafeAddressOf.

/// Return an UnsafePointer to the storage used for `object`.  There's
/// not much you can do with this other than use it to identify the
/// object

Cepat 3

Untuk Swift 3, gunakan withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}
Drew
sumber
2
unsafeAddressOf () hanya berfungsi untuk jenis kelas (seperti @Nick tunjukkan di bawah). Dengan demikian, jawaban ini hanya berfungsi jika Foundation diimpor dan String dijembatani ke NSString. Dalam Swift biasa, String adalah tipe nilai dan unsafeAddressOf tidak dapat digunakan untuk mengambil alamatnya (upaya menghasilkan kesalahan kompilasi).
Stephen Schaub
29
Bagaimana jika saya ingin mencetak alamat dengan nilai tidak berubah dengan Swift 3? withUnsafePointermengakibatkan cannot pass immutable value as inout argumentkesalahan.
Alexander Vasenin
12
Meskipun diterima dan dipilih sebagai jawaban tertinggi, tetap memberikan hasil yang salah . Contoh: print(self.description)cetak <MyViewController: 0x101c1d580>, kami menggunakannya sebagai referensi. var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }cetakan 0x16fde4028yang alamatnya jelas berbeda. Adakah yang bisa menjelaskan mengapa?
Alexander Vasenin
4
BTW, ini mencetak 0x101c1d580seperti yang diharapkan:print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
Alexander Vasenin
8
@ nyg Jawaban Anda memberi saya petunjuk untuk penyebab kesalahan aktual: UnsafePointeradalah sebuah struct, jadi untuk mencetak alamat yang ditunjuknya (dan bukan struct itu sendiri) Anda harus mencetak String(format: "%p", $0.pointee)!
Alexander Vasenin
214

Catatan: Ini untuk jenis referensi.

Swift 4/5:

print(Unmanaged.passUnretained(someVar).toOpaque())

Mencetak alamat memori someVar. (terima kasih kepada @Ying)


Swift 3.1:

print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())

Mencetak alamat memori someVar.


Woodstock
sumber
2
Xcode 8.2.1 mengoreksi otomatis memberi tahu saya sekarangprint(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Jeff
2
Bukankah ini hanya benar jika someVar adalah objek. Jika someVar kebetulan menjadi tipe nilai seperti struct, ini akan memberikan alamat yang berbeda setiap kali dieksekusi.
OutOnAWeekend
3
@OutOnAWeekend Anda benar, kemungkinan besar karena struktur disalin ketika dilewatkan sebagai argumen. Menggunakan Unmanageditu dapat dilakukan seperti ini: print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque()).
Nyg
1
Pada Swift 4, saya bisa mendapatkan mantra ini untuk dicetak juga - Unmanaged.passUnretained(someVar).toOpaque()(tidak perlu spesifikasi umum)
Ying
2
Jawaban Swift 4 sempurna. Jika Anda juga ingin mendapatkan representasi string tanpa mencetak, saya sarankan debugDescriptionuntuk menambahkannya .
Patrick
51

Perhatikan bahwa jawaban ini sudah cukup lama. Banyak metode yang dijelaskannya tidak lagi berfungsi. Khususnya .coretidak dapat diakses lagi.

Namun, jawaban @ drew benar dan sederhana:

Ini sekarang bagian dari perpustakaan standar: unsafeAddressOf.

Jadi jawaban untuk pertanyaan Anda adalah:

println(" str value \(str) has address: \(unsafeAddressOf(str))")

Inilah jawaban asli yang ditandai benar (untuk keturunan / kesopanan):

Swift "menyembunyikan" pointer, tetapi mereka masih ada di bawah tenda. (karena runtime membutuhkannya, dan untuk alasan kompatibilitas dengan Objc dan C)

Ada beberapa hal yang perlu diketahui, tetapi pertama-tama bagaimana cara mencetak alamat memori dari Swift String?

    var aString : String = "THIS IS A STRING"
    NSLog("%p", aString.core._baseAddress)  // _baseAddress is a COpaquePointer
   // example printed address 0x100006db0

Ini mencetak alamat memori dari string, jika Anda membuka XCode -> Debug Workflow -> View Memory dan pergi ke alamat yang dicetak, Anda akan melihat data mentah dari string. Karena ini adalah string literal, ini adalah alamat memori di dalam penyimpanan biner (bukan stack atau heap).

Namun, jika Anda melakukannya

    var aString : String = "THIS IS A STRING" + "This is another String"
    NSLog("%p", aString.core._baseAddress)

    // example printed address 0x103f30020

Ini akan berada di tumpukan, karena string dibuat saat runtime

CATATAN: .core._baseAddress tidak didokumentasikan, saya menemukannya mencari di variabel inspector, dan mungkin disembunyikan di masa depan

_baseAddress tidak tersedia di semua jenis, di sini contoh lain dengan CInt

    var testNumber : CInt = 289
    takesInt(&testNumber)

Di mana takesIntfungsi pembantu C seperti ini

void takesInt(int *intptr)
{
    printf("%p", intptr);
}

Di sisi Swift, fungsi ini adalah takesInt(intptr: CMutablePointer<CInt>), jadi dibutuhkan CMutablePointer ke CInt, dan Anda bisa mendapatkannya dengan & varname

Fungsi mencetak 0x7fff5fbfed98, pada alamat memori ini Anda akan menemukan 289 (dalam notasi heksadesimal). Anda dapat mengubah kontennya dengan*intptr = 123456

Sekarang, beberapa hal lain yang perlu diketahui.

String, dengan cepat, adalah tipe primitif, bukan objek.
CInt adalah tipe Swift yang dipetakan ke Tipe C int.
Jika Anda ingin alamat memori suatu objek, Anda harus melakukan sesuatu yang berbeda.
Swift memiliki beberapa Tipe Pointer yang dapat digunakan saat berinteraksi dengan C, dan Anda dapat membacanya di sini: Tipe Swift Pointer
Selain itu, Anda dapat memahami lebih lanjut tentang mereka yang mengeksplorasi deklarasi mereka (cmd + klik pada jenisnya), untuk memahami cara mengonversi jenis pointer ke yang lain

    var aString : NSString = "This is a string"  // create an NSString
    var anUnmanaged = Unmanaged<NSString>.passUnretained(aString)   // take an unmanaged pointer
    var opaque : COpaquePointer = anUnmanaged.toOpaque()   // convert it to a COpaquePointer
    var mut : CMutablePointer = &opaque   // this is a CMutablePointer<COpaquePointer>

    printptr(mut)   // pass the pointer to an helper function written in C

printptr adalah fungsi pembantu C yang saya buat, dengan implementasi ini

void printptr(void ** ptr)
{
    printf("%p", *ptr);
}

Sekali lagi, contoh alamat dicetak:, 0x6000000530b0dan jika Anda pergi melalui inspektur memori Anda akan menemukan NSString Anda

Satu hal yang dapat Anda lakukan dengan pointer di Swift (ini bahkan dapat dilakukan dengan parameter inout)

    func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>) 
    {
        stringa.memory = "String Updated";
    }

    var testString : NSString = "test string"
    println(testString)
    playWithPointer(&testString)
    println(testString)

Atau, berinteraksi dengan Objc / c

// objc side
+ (void)writeString:(void **)var
{
    NSMutableString *aString = [[NSMutableString alloc] initWithFormat:@"pippo %@", @"pluto"];
    *var = (void *)CFBridgingRetain(aString);   // Retain!
}

// swift side
var opaque = COpaquePointer.null()   // create a new opaque pointer pointing to null
TestClass.writeString(&opaque)
var string = Unmanaged<NSString>.fromOpaque(opaque).takeRetainedValue()
println(string)
// this prints pippo pluto
LombaX
sumber
ya, pointer harus keluar tetapi tidak hanya untuk alasan kompatibilitas seperti yang Anda rujuk. pointer biasanya digunakan oleh sistem operasi. bahkan jika bahasanya adalah bahasa tingkat tinggi, pointer harus ada dalam bahasa apa pun kapan saja di mesin sistem operasi.
holex
Saya mengatakan "untuk alasan kompatibilitas DAN karena runtime membutuhkannya" :-) pernyataan kedua merangkum apa yang Anda katakan (saya berasumsi bahwa seorang programmer tahu dan memahaminya, jadi saya menghabiskan beberapa kata)
LombaX
Saya menganggap ini tidak berlaku lagi?
aleclarson
Iya. Saya mengedit jawaban yang benar dari @Drew ke dalamnya.
Rog
@LombaX kita hanya bisa mencetak alamat tipe referensi? Tidak bisakah saya mencetak alamat variabel?
AbhimanyuAryan
21

Untuk mendapatkan alamat (tumpukan) dari suatu objek

func address<T: AnyObject>(o: T) -> Int {
    return unsafeBitCast(o, Int.self)
}

class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970

( Sunting: Swift 1.2 sekarang termasuk fungsi serupa yang disebut unsafeAddressOf.)

Dalam Objective-C ini akan menjadi [NSString stringWithFormat:@"%p", o].

oadalah referensi ke instance. Jadi, jika oditugaskan ke variabel lain o2, alamat yang dikembalikan untuk o2akan sama.

Ini tidak berlaku untuk struct (termasuk String) dan tipe primitif (seperti Int), karena mereka tinggal langsung di stack. Tetapi kita dapat mengambil lokasi di stack.

Untuk mendapatkan (tumpukan) alamat struct, tipe bawaan atau referensi objek

func address(o: UnsafePointer<Void>) -> Int {
    return unsafeBitCast(o, Int.self)
}

println(NSString(format: "%p", address(&o))) // -> 0x10de02ce0

var s = "A String"
println(NSString(format: "%p", address(&s))) // -> 0x10de02ce8

var i = 55
println(NSString(format: "%p", address(&i))) // -> 0x10de02d00

Dalam Objective-C ini akan menjadi [NSString stringWithFormat:@"%p", &o]atau [NSString stringWithFormat:@"%p", &i].

sadalah struct. Jadi jika sditugaskan ke variabel lain s2, nilainya akan disalin dan alamat yang dikembalikan s2akan berbeda.

Bagaimana itu cocok bersama (pointer rekap)

Seperti di Objective-C, ada dua alamat berbeda yang terkait dengannya o. Yang pertama adalah lokasi objek, yang kedua adalah lokasi referensi (atau pointer) ke objek.

Ya, ini berarti bahwa isi alamat 0x7fff5fbfe658 adalah angka 0x610000001111 seperti yang dapat dikatakan oleh debugger kepada kami:

(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0

Jadi, kecuali untuk string yang menjadi struct, secara internal semua ini cukup banyak bekerja sama dengan di (Objective-) C.

(Lancar pada Xcode 6.3)

nschum
sumber
Hmm. Mendapatkan alamat tumpukan properti objek tidak konsisten. Ada ide? Lihatlah intinya!
aleclarson
Properti objek berada di heap, bukan stack. Ketika Anda melewati properti instance kelas sebagai UnsafePointer, Swift sebenarnya menyalin nilai terlebih dahulu dan Anda mendapatkan alamat salinannya. Saya menduga itu adalah untuk mencegah kode C dari menghindari antarmuka objek dan menyebabkan keadaan tidak konsisten. Saya tidak tahu apakah ada cara untuk itu.
nschum
Inilah utas yang saya buat di Forum Pengembang Apple . Beberapa balasan bagus di sana.
aleclarson
20

TL; DR

struct MemoryAddress<T>: CustomStringConvertible {

    let intValue: Int

    var description: String {
        let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
        return String(format: "%0\(length)p", intValue)
    }

    // for structures
    init(of structPointer: UnsafePointer<T>) {
        intValue = Int(bitPattern: structPointer)
    }
}

extension MemoryAddress where T: AnyObject {

    // for classes
    init(of classInstance: T) {
        intValue = unsafeBitCast(classInstance, to: Int.self)
        // or      Int(bitPattern: Unmanaged<T>.passUnretained(classInstance).toOpaque())
    }
}

/* Testing */

class MyClass { let foo = 42 }
var classInstance = MyClass()
let classInstanceAddress = MemoryAddress(of: classInstance) // and not &classInstance
print(String(format: "%018p", classInstanceAddress.intValue))
print(classInstanceAddress)

struct MyStruct { let foo = 1 } // using empty struct gives weird results (see comments)
var structInstance = MyStruct()
let structInstanceAddress = MemoryAddress(of: &structInstance)
print(String(format: "%018p", structInstanceAddress.intValue))
print(structInstanceAddress)

/* output
0x0000000101009b40
0x0000000101009b40
0x00000001005e3000
0x00000001005e3000
*/

( Intisari )


Di Swift kami berurusan dengan tipe nilai (struktur) atau tipe referensi (kelas). Ketika melakukan:

let n = 42 // Int is a structure, i.e. value type

Beberapa memori dialokasikan pada alamat X, dan pada alamat ini kita akan menemukan nilai 42. Melakukan &nmembuat pointer menunjuk ke alamat X, oleh karena itu &nmemberitahu kita di mana nberada.

(lldb) frame variable -L n
0x00000001005e2e08: (Int) n = 42
(lldb) memory read -c 8 0x00000001005e2e08
0x1005e2e08: 2a 00 00 00 00 00 00 00 // 0x2a is 42

Ketika melakukan:

class C { var foo = 42, bar = 84 }
var c = C()

Memori dialokasikan di dua tempat:

  • di alamat Y tempat data instance kelas berada dan
  • di alamat X di mana referensi instance kelas berada.

Seperti yang dikatakan, kelas adalah tipe referensi: jadi nilai cterletak di alamat X, di mana kita akan menemukan nilai Y. Dan di alamat Y + 16 kita akan menemukan foodan di alamat Y + 24 kita akan menemukan bar( pada + 0 dan + 8 kita akan menemukan tipe data dan jumlah referensi, saya tidak bisa memberi tahu Anda lebih banyak tentang ini ...).

(lldb) frame variable c // gives us address Y
(testmem.C) c = 0x0000000101a08f90 (foo = 42, bar = 84)
(lldb) memory read 0x0000000101a08f90 // reading memory at address Y
0x101a08f90: e0 65 5b 00 01 00 00 00 02 00 00 00 00 00 00 00
0x101a08fa0: 2a 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00

0x2aadalah 42 (foo) dan 0x5484 (bar).

Dalam kedua kasus, menggunakan &natau&c akan memberi kami alamat X. Untuk tipe nilai, itulah yang kami inginkan, tetapi bukan untuk tipe referensi.

Ketika melakukan:

let referencePointer = UnsafeMutablePointer<C>(&c)

Kami membuat pointer pada referensi, yaitu pointer yang menunjuk ke alamat X. Hal yang sama saat menggunakan withUnsafePointer(&c) {}.

(lldb) frame variable referencePointer
(UnsafeMutablePointer<testmem.C>) referencePointer = 0x00000001005e2e00 // address X
(lldb) memory read -c 8 0x00000001005e2e00 // read memory at address X
0x1005e2e00: 20 ec 92 01 01 00 00 00 // contains address Y, consistent with result below:
(lldb) frame variable c
(testmem.C) c = 0x000000010192ec20 (foo = 42, bar = 84)

Sekarang kita memiliki pemahaman yang lebih baik tentang apa yang terjadi di bawah tenda, dan bahwa kita sekarang bahwa pada alamat X kita akan menemukan alamat Y (yang mana kita inginkan) kita dapat melakukan hal berikut untuk mendapatkannya:

let addressY = unsafeBitCast(c, to: Int.self)

Memverifikasi:

(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)

Ada cara lain untuk melakukan ini:

let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }

toOpaque() sebenarnya menelepon unsafeBitCast(c, to: UnsafeMutableRawPointer.self) .

Saya harap ini membantu ... itu berhasil untuk saya 😆.

nyg
sumber
Hanya memperhatikan bahwa ketika mencoba untuk mencetak alamat struct yang sama melalui 2 contoh berbeda MemoryLocationmenghasilkan 2 alamat yang berbeda.
user1046037
@ user1046037 Terima kasih, membuat perubahan untuk init kelas. Saya juga mendapatkan dua alamat yang berbeda, tetapi hanya ketika saya menggunakan struct kosong. Menggunakan struct kosong selalu memberi saya hasil yang aneh. Tebakan saya adalah kompiler membuat beberapa optimisasi ...
nyg
@ user1046037 Periksa: pastebin.com/mpd3ujw2 . Rupanya, semua struct kosong menunjuk ke alamat memori yang sama. Namun, ketika kita ingin menyimpan pointer dalam sebuah variabel, itu akan membuat salinannya (atau struct?) ...
nyg
Itu menarik tetapi ketika dicetak dua kali mencetak alamat memori yang berbeda. Sama halnya dengan jawaban di atas juga.
user1046037
@ user1046037 Saya tidak yakin saya mengerti apa yang Anda maksud, apakah Anda memiliki beberapa kode? (Saya selalu mendapatkan alamat memori yang sama)
nyg
15

Jenis referensi:

  • Masuk akal untuk mendapatkan alamat memori dari tipe referensi karena mewakili identitas.
  • === operator identitas digunakan untuk memeriksa 2 objek yang menunjuk ke referensi yang sama.
  • Gunakan ObjectIdentifieruntuk mendapatkan alamat memori

Kode:

class C {}

let c1 = C()
let c2 = c1

//Option 1:
print("c1 address: \(Unmanaged.passUnretained(c1).toOpaque())") 

//Option 2:
let o1 = ObjectIdentifier(c1)
let o2 = ObjectIdentifier(c2)

print("o1 -> c1 = \(o1)")
print("o2 -> c2 = \(o2)")

if o1 == o2 {
    print("c1 = c2")
} else {
    print("c1 != c2")
}

//Output:
//c1 address: 0x000060c000005b10
//o1 -> c1 = ObjectIdentifier(0x000060c000005b10)
//o2 -> c2 = ObjectIdentifier(0x000060c000005b10)
//c1 = c2

Jenis nilai:

  • Kebutuhan untuk mendapatkan alamat memori dari suatu tipe nilai tidak terlalu penting (karena itu adalah nilai) dan penekanannya akan lebih pada kesetaraan nilai.
pengguna1046037
sumber
12

Gunakan ini saja:

print(String(format: "%p", object))
pavelcauselov
sumber
Jika Anda mendapat kompiler komplain tentang " MyClass?" tidak sesuai dengan CVarArg, Anda bisa melakukannya extension Optional : CVarArg { }. Kalau tidak, ini sepertinya mencetak alamat tanpa semua kegilaan "tidak aman" dari jawaban lain.
Devin Lane
Itu membutuhkan implementasi var _cVarArgEncoding: [Int]on CVarArg. Tidak jelas bagaimana itu harus dilaksanakan.
Yuchen Zhong
10

Jika Anda hanya ingin melihat ini di debugger dan tidak melakukan hal lain dengan itu, tidak perlu benar-benar mendapatkan Intpointer. Untuk mendapatkan representasi string dari alamat objek dalam memori, cukup gunakan sesuatu seperti ini:

public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension's target or place the logic in a global function
    public var pointerString: String {
        return String(format: "%p", self)
    }
}

Contoh penggunaan:

print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...

Selain itu, ingatlah bahwa Anda cukup mencetak objek tanpa mengesampingkannya description, dan itu akan menunjukkan alamat penunjuknya di samping teks yang lebih deskriptif (jika sering samar).

print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...
Ben Leggiero
sumber
1
Harap temani downvotes apa pun dengan komentar yang menjelaskan alasannya, jadi saya dan siapa pun yang datang ke sini tahu mengapa ini adalah solusi yang buruk :)
Ben Leggiero
1
Sederhana dan rapi!
badhanganesh
9

Cepat 5

extension String {
    static func pointer(_ object: AnyObject?) -> String {
        guard let object = object else { return "nil" }
        let opaque: UnsafeMutableRawPointer = Unmanaged.passUnretained(object).toOpaque()
        return String(describing: opaque)
    }
}

Pemakaian:

print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698

print("nil: \(String.pointer(nil))")
// nil: nil
neoneye
sumber
Jawaban ini salah. Jika Anda membuat dua instance dari kelas yang sama, itu akan mengembalikan alamat memori yang sama untuk kedua instance. Unmanaged.passUnretained(myObject).toOpaque()bekerja dengan baik sebagai gantinya.
Padraig
@ Padraig Terima kasih, saya telah memperbarui kode Anda. Sayangnya sekarang dibutuhkan AnyObjectparameter. Saya lebih suka Anysebagai tipe input.
neoneye
6

Di Swift4 tentang Array:

    let array1 = [1,2,3]
    let array2 = array1
    array1.withUnsafeBufferPointer { (point) in
        print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
    }
    array2.withUnsafeBufferPointer { (point) in
        print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
    }
SenKe
sumber
1
menyelamatkan hari saya. Seharusnya ada lencana "akuisisi terbaru yang paling berguna"
Anton Tropashko
Memang, ini adalah satu-satunya pendekatan yang dicetak saya self?.array.
Rostyslav Druzhchenko
4

Jawaban lain baik-baik saja, meskipun saya sedang mencari cara untuk mendapatkan alamat pointer sebagai integer:

let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)

/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int

Sedikit tindak lanjut.

Charlie Monroe
sumber
Lihat di bawah untuk versi jawaban ini untuk Swift 3.
RenniePet
3

Jawaban @Drew menyediakan hanya dapat digunakan untuk tipe kelas.
Jawaban @nschum hanya bisa untuk tipe struct.

Namun jika Anda menggunakan metode kedua untuk mendapatkan alamat array dengan elemen tipe nilai. Swift akan menyalin seluruh array karena dalam Swift array adalah copy-on-write dan Swift tidak dapat memastikannya berperilaku seperti ini setelah melewati kontrol ke C / C ++ (Yang dipicu dengan menggunakan &untuk mendapatkan alamat). Dan jika Anda menggunakan metode pertama sebagai gantinya, itu akan secara otomatis dikonversi Arrayke NSArrayyang pasti sesuatu yang tidak kita inginkan.

Jadi cara paling sederhana dan terpadu yang saya temukan adalah menggunakan instruksi lldb frame variable -L yourVariableName.

Atau Anda dapat menggabungkan jawaban mereka:

func address(o: UnsafePointer<Void>) {
    let addr = unsafeBitCast(o, Int.self)
    print(NSString(format: "%p", addr))
}

func address<T: AnyObject>(o: T) -> String{
    let addr = unsafeBitCast(o, Int.self)
    return NSString(format: "%p", addr) as String
}
Nick Allen
sumber
3

Ini untuk Swift 3.

Seperti @CharlieMonroe saya ingin mendapatkan alamat sebagai integer. Secara khusus, saya ingin alamat objek Thread untuk digunakan sebagai ID utas dalam modul logging diagnostik, untuk situasi di mana tidak ada nama utas yang tersedia.

Berdasarkan kode Charlie Monroe, inilah yang saya buat sejauh ini. Tetapi waspadalah, saya sangat baru di Swift, ini mungkin tidak benar ...

  // Convert the memory address of the current Thread object into an Int for use as a thread ID
  let objPtr = Unmanaged.passUnretained(Thread.current).toOpaque()
  let onePtr = UnsafeMutableRawPointer(bitPattern: 1)!  // 1 used instead of 0 to avoid crash
  let rawAddress : Int64 = onePtr.distance(to: objPtr) + 1  // This may include some high-order bits
  let address = rawAddress % (256 * 1024 * 1024 * 1024)  // Remove high-order bits

Pernyataan terakhir ada karena tanpa itu saya mendapatkan alamat seperti 0x60000007DB3F. Operasi modulo dalam pernyataan terakhir mengubahnya menjadi 0x7DB3F.

RenniePet
sumber
3

Solusi saya di Swift 3

extension MyClass: CustomStringConvertible {
    var description: String {
        return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
    }
}

kode ini membuat deskripsi seperti deskripsi default <MyClass: 0x610000223340>

EvGeniy ​​Ilyin
sumber
2

Ini tentu bukan cara tercepat atau teraman untuk melakukannya. Tapi hal ini bekerja untukku. Ini akan memungkinkan subclass nsobject untuk mengadopsi properti ini.

public extension NSObject {
    public var memoryAddress : String? {
        let str = "\(self.self)".components(separatedBy: ": ")
        guard str.count > 1 else { return nil }
        return str[1].replacingOccurrences(of: ">", with: "")            
    }
}

//usage 
let foo : String! = "hello"
Swift.print(foo.memoryAddress) // prints 0x100f12980
Charlton Provatas
sumber
terima kasih atas umpan balik Jeff, saya akan memperbarui jawabannya
Charlton Provatas
1
Lupakan! Itu kesalahan saya! Kode Anda berfungsi baik dengan kelas Swift murni. Maaf atas kesalahannya.
Jeff