Szybkie drukowanie zmiennych adresów pamięci

165

Czy w ogóle istnieje możliwość symulacji [NSString stringWithFormat:@"%p", myVar], z Objective-C, w nowym języku Swift?

Na przykład:

let str = "A String"
println(" str value \(str) has address: ?")
apouche
źródło
2
W [NSString stringWithFormat:@"%p", myVar], myVarmusi być wskaźnikiem. W kodzie Swift strnie jest wskaźnikiem. Więc porównanie nie ma zastosowania.
user102008
5
Warto zauważyć, że przynajmniej kiedy to piszę, powyższe dwa komentarze są niepoprawne.
Ben Leggiero

Odpowiedzi:

112

Szybki 2

Jest obecnie częścią standardowej biblioteki: 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

Szybki 3

W przypadku Swift 3 użyj withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}
Rysował
źródło
2
unsafeAddressOf () działa tylko dla typów klas (jak @Nick wskazuje poniżej). Dlatego ta odpowiedź działa tylko wtedy, gdy Foundation jest importowana, a String jest połączony mostem z NSString. W zwykłym języku Swift String jest typem wartości i nie można użyć unsafeAddressOf do przejęcia jego adresu (próba skutkuje błędem kompilacji).
Stephen Schaub,
29
A jeśli chcę wydrukować adres o niezmiennej wartości w Swift 3? withUnsafePointerskutkuje cannot pass immutable value as inout argumentbłędem.
Alexander Vasenin
12
Mimo że jest to zaakceptowana i najwyższa głosowana odpowiedź, nadal daje błędne wyniki. Przykład: print(self.description)wydruki <MyViewController: 0x101c1d580>, używamy go jako odniesienia. var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }wydruki, 0x16fde4028które są wyraźnie innym adresem. Czy ktoś może wyjaśnić, dlaczego?
Alexander Vasenin
4
Przy okazji, to drukuje 0x101c1d580zgodnie z oczekiwaniami:print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
Alexander Vasenin
8
@nyg Twoja odpowiedź dała mi wskazówkę dotyczącą rzeczywistej przyczyny błędu: UnsafePointerjest strukturą, więc aby wydrukować adres, na który wskazuje (a nie samą strukturę), musisz wydrukować String(format: "%p", $0.pointee)!
Alexander Vasenin,
213

Uwaga: dotyczy to typów referencyjnych.

Swift 4/5:

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

Drukuje adres pamięci someVar. (dzięki @Ying)


Swift 3.1:

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

Drukuje adres pamięci someVar.


Woodstock
źródło
2
Autokorekta Xcode 8.2.1 mówi mi, że jest terazprint(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Jeff,
2
Czy nie byłoby to prawdą tylko wtedy, gdy someVar jest obiektem. Jeśli someVar jest typem wartości, takim jak struct, to za każdym razem, gdy jest wykonywany, poda inny adres.
OutOnAWeekend
3
@OutOnAWeekend Masz rację, najprawdopodobniej dlatego, że struktura jest kopiowana, gdy jest przekazywana jako argument. Korzystanie Unmanagedmożna to zrobić tak: print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque()).
nyg
1
Począwszy od Swift 4, mogłem również wydrukować to zaklęcie - Unmanaged.passUnretained(someVar).toOpaque()(nie ma potrzeby ogólnej specyfikacji)
Ying
2
Odpowiedź Swift 4 jest idealna. Jeśli chcesz również uzyskać reprezentację ciągu bez drukowania, polecam dodaniedebugDescription na końcu tego.
Patrick,
51

Zauważ, że ta odpowiedź była dość stara. Wiele metod, które opisuje, już nie działa. W szczególności .corenie można już uzyskać do nich dostępu.

Jednak odpowiedź @ drew jest poprawna i prosta:

Jest to teraz część biblioteki standardowej: unsafeAddressOf.

Tak więc odpowiedź na Twoje pytania brzmi:

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

Oto oryginalna odpowiedź, która została oznaczona jako poprawna (dla potomności / grzeczności):

Szybkie „chowa” wskazówki, ale nadal istnieją pod maską. (ponieważ środowisko wykonawcze tego potrzebuje i ze względu na zgodność z Objc i C)

Jest jednak kilka rzeczy, które należy wiedzieć, ale najpierw jak wydrukować adres pamięci Swift String?

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

Spowoduje to wyświetlenie adresu pamięci ciągu, jeśli otworzysz XCode -> Debug Workflow -> View Memory i przejdziesz do wydrukowanego adresu, zobaczysz nieprzetworzone dane ciągu. Ponieważ jest to literał łańcuchowy, jest to adres pamięci wewnątrz magazynu pliku binarnego (nie stosu ani sterty).

Jednak jeśli to zrobisz

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

    // example printed address 0x103f30020

Będzie to na stosie, ponieważ ciąg jest tworzony w czasie wykonywania

UWAGA: .core._baseAddress nie jest udokumentowany, znalazłem go w inspektorze zmiennych i może być ukryty w przyszłości

_baseAddress nie jest dostępny we wszystkich typach, tutaj inny przykład z CInt

    var testNumber : CInt = 289
    takesInt(&testNumber)

Gdzie takesIntjest taka funkcja pomocnicza C.

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

Po stronie Swift ta funkcja jest takesInt(intptr: CMutablePointer<CInt>) więc pobiera CMutablePointer do CInt i możesz ją uzyskać za pomocą & varname

Funkcja drukuje 0x7fff5fbfed98 , a pod tym adresem pamięci znajduje się 289 (w notacji szesnastkowej). Możesz zmienić jego zawartość za pomocą*intptr = 123456

A teraz kilka innych rzeczy, które warto wiedzieć.

String w swift jest typem pierwotnym, a nie obiektem.
CInt jest typem Swift zamapowanym na typ int C.
Jeśli chcesz mieć adres pamięci obiektu, musisz zrobić coś innego.
Swift ma kilka typów wskaźników, których można używać podczas interakcji z C, i możesz o nich przeczytać tutaj: Typy wskaźników Swift
Ponadto możesz dowiedzieć się więcej o nich, badając ich deklarację (cmd + kliknij typ), aby zrozumieć, jak konwertować rodzaj wskaźnika do innego

    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 jest funkcją pomocniczą języka C, którą stworzyłem, z tą implementacją

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

Ponownie, przykład wydrukowanego adresu: 0x6000000530b0 a jeśli przejdziesz przez inspektora pamięci, znajdziesz swój NSString

Jedna rzecz, którą możesz zrobić ze wskaźnikami w Swift (można to nawet zrobić z parametrami inout)

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

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

Lub, wchodząc w interakcję z 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
źródło
tak, wskaźnik musi wyjść, ale nie tylko ze względu na kompatybilność, o której mówiłeś. wskaźniki zwykle używane przez system operacyjny. nawet jeśli jest to język wysokiego poziomu, wskaźniki muszą istnieć w dowolnym języku w dowolnym momencie w silniku systemu operacyjnego.
holex
Powiedziałem "ze względu na kompatybilność ORAZ ponieważ środowisko wykonawcze tego potrzebuje" :-) druga instrukcja podsumowuje to, co mówisz (zakładam, że programista to wie i rozumie, więc poświęciłem kilka słów)
LombaX
Zakładam, że to już nie dotyczy?
aleclarson
Tak. Wpisałem do niej poprawną odpowiedź z @Drew.
Rog
@LombaX możemy wydrukować tylko adres typu referencyjnego? Nie mogę wydrukować adresu zmiennych?
AbhimanyuAryan
21

Aby uzyskać adres (sterty) obiektu

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

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

( Edycja: Swift 1.2 zawiera teraz podobną funkcję o nazwie unsafeAddressOf.)

W Objective-C tak będzie [NSString stringWithFormat:@"%p", o].

ojest odniesieniem do instancji. Więc jeśli ozostanie przypisana do innej zmiennej o2, zwracany adres o2będzie taki sam.

Nie dotyczy to struktur (w tym String) i typów pierwotnych (takich jak Int), ponieważ te żyją bezpośrednio na stosie. Ale możemy pobrać lokalizację na stosie.

Aby uzyskać adres (stosu) struktury, typ wbudowany lub odwołanie do obiektu

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

W Objective-C byłoby to [NSString stringWithFormat:@"%p", &o]lub [NSString stringWithFormat:@"%p", &i].

sjest strukturą. Jeśli więc szostanie przypisana do innej zmiennej s2, wartość zostanie skopiowana, a zwracany adres dla s2będzie inny.

Jak to pasuje do siebie (podsumowanie wskaźnika)

Podobnie jak w Objective-C, istnieją dwa różne adresy powiązane z o. Pierwsza to lokalizacja obiektu, druga to lokalizacja odniesienia (lub wskaźnika) do obiektu.

Tak, to znaczy, że zawartość adresu 0x7fff5fbfe658 to numer 0x6100000011d0, ponieważ debugger może nam powiedzieć:

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

Tak więc, z wyjątkiem łańcuchów będących strukturami, wewnętrznie to wszystko działa prawie tak samo jak w (Objective-) C.

(Aktualne od Xcode 6.3)

nschum
źródło
Hmm. Pobieranie adresu stosu właściwości obiektu nie jest spójne. Jakieś pomysły? Sprawdź to sedno!
aleclarson,
Właściwości obiektu znajdują się na stercie, a nie na stosie. Kiedy przekazujesz właściwość instancji klasy jako UnsafePointer, Swift faktycznie kopiuje wartość jako pierwsza, a Ty otrzymujesz adres kopii. Podejrzewam, że ma to zapobiec omijaniu przez kod C interfejsu obiektu i powodowaniu niespójnego stanu. Nie wiem, czy jest na to sposób.
nschum
Oto wątek, który utworzyłem na forach Apple Developer . Są tam dobre odpowiedzi.
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
*/

( Streszczenie )


W Swift mamy do czynienia z typami wartości (strukturami) lub typami referencyjnymi (klasami). Robiąc:

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

Część pamięci jest alokowana pod adresem X i pod tym adresem znajdziemy wartość 42. Doing &ntworzy wskaźnik wskazujący na adres X, a zatem &nmówi nam, gdzie nsię znajduje.

(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

Robiąc:

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

Pamięć jest przydzielana w dwóch miejscach:

  • pod adresem Y, gdzie znajdują się dane instancji klasy i
  • pod adresem X, gdzie znajduje się odwołanie do instancji klasy.

Jak już powiedziano, klasy są typami referencyjnymi: więc wartość cznajduje się pod adresem X, pod którym znajdziemy wartość Y. A pod adresem Y + 16 znajdziemy, fooa pod adresem Y + 24 znajdziemy bar( na + 0 i + 8 znajdziemy dane typu i liczbę referencji, nie mogę powiedzieć więcej na ten temat ...).

(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

0x2awynosi 42 (foo) i 0x5484 (bar).

W obu przypadkach użycie &nlub&c da nam adres X. W przypadku typów wartości właśnie tego chcemy, ale nie w przypadku typów referencyjnych.

Robiąc:

let referencePointer = UnsafeMutablePointer<C>(&c)

Tworzymy wskaźnik na referencję, tj. Wskaźnik, który wskazuje na adres X. To samo przy używaniu 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)

Teraz, gdy mamy lepsze zrozumienie tego, co dzieje się pod maską, i że teraz pod adresem X znajdziemy adres Y (który jest tym, którego potrzebujemy), możemy wykonać następujące czynności, aby go uzyskać:

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

Weryfikacja:

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

Można to zrobić na inne sposoby:

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

toOpaque()faktycznie dzwoni unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

Mam nadzieję, że to pomogło ... pomogło mi 😆.

nyg
źródło
Właśnie zauważyłem, że podczas próby wydrukowania adresu tej samej struktury za pomocą 2 różnych instancji programu MemoryLocationtworzy 2 różne adresy.
user1046037
@ user1046037 Dzięki, dokonałem zmiany dla init klasy. Otrzymuję również dwa różne adresy, ale tylko wtedy, gdy używam pustej struktury. Używanie pustej struktury zawsze daje dziwne rezultaty. Domyślam się, że kompilator wprowadza pewne optymalizacje ...
nyg
@ user1046037 Sprawdź: pastebin.com/mpd3ujw2 . Najwyraźniej wszystkie puste struktury wskazują na ten sam adres pamięci. Jeśli jednak chcemy przechowywać wskaźnik w zmiennej, utworzy ona jego kopię (lub strukturę?) ...
nyg
To interesujące, ale po dwukrotnym wydrukowaniu drukuje różne adresy pamięci. To samo dotyczy powyższych odpowiedzi.
user1046037
@ user1046037 Nie jestem pewien, czy rozumiem, co masz na myśli, czy masz jakiś kod? (Zawsze otrzymuję ten sam adres pamięci)
nyg
15

Typy referencyjne:

  • Uzyskanie adresu pamięci typu referencyjnego ma sens, ponieważ reprezentuje on tożsamość.
  • === Operator tożsamości służy do sprawdzania, czy 2 obiekty wskazują na to samo odniesienie.
  • Użyj, ObjectIdentifieraby uzyskać adres pamięci

Kod:

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

Typy wartości:

  • Potrzeba uzyskania adresu pamięci typu wartości nie ma większego znaczenia (ponieważ jest to wartość), a nacisk kładziony byłby bardziej na równość wartości.
user1046037
źródło
12

Po prostu użyj tego:

print(String(format: "%p", object))
pavelcauselov
źródło
Jeśli otrzymasz skargę kompilatora dotyczącą MyClass?niezgodności „ ” z CVarArg, możesz to zrobić extension Optional : CVarArg { }. W przeciwnym razie wydaje się, że wypisuje adresy bez „niebezpiecznego” szaleństwa innych odpowiedzi.
Devin Lane
Wymaga implementacji var _cVarArgEncoding: [Int]on CVarArg. Nie jest jasne, jak należy to wdrożyć.
Yuchen Zhong
10

Jeśli chcesz po prostu zobaczyć to w debugerze i nie robić z tym nic więcej, nie ma potrzeby pobierania Intwskaźnika. Aby uzyskać ciąg znaków reprezentujący adres obiektu w pamięci, użyj czegoś takiego:

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)
    }
}

Przykładowe użycie:

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

Ponadto pamiętaj, że możesz po prostu wydrukować obiekt bez nadpisywania jego description, a on pokaże swój adres wskaźnika obok bardziej opisowego (jeśli często tajemniczego) tekstu.

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
źródło
1
Proszę towarzyszyć żadnych downvotes z komentarzem wyjaśniającym, dlaczego więc i ktoś przychodzi tutaj wie, dlaczego jest to słabe rozwiązanie :)
Ben Leggiero
1
Proste i schludne!
badhanganesh
9

Szybki 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)
    }
}

Stosowanie:

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

print("nil: \(String.pointer(nil))")
// nil: nil
neoneye
źródło
Ta odpowiedź jest nieprawidłowa. Jeśli utworzysz dwa wystąpienia tej samej klasy, zwróci ten sam adres pamięci dla obu wystąpień. Unmanaged.passUnretained(myObject).toOpaque()zamiast tego działa prawidłowo.
Padraig
@Padraig Dzięki, zaktualizowałem Twój kod. Niestety teraz przyjmuje AnyObjectparametr. Wolałbym Anyjako typ wejścia.
neoneye
6

W Swift4 o 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
źródło
1
uratował mój dzień. Powinna być odznaka "najbardziej przydatna ostatnia taka akwizycja"
Anton Tropashko
Rzeczywiście, jest to jedyne podejście, które spowodowało wydrukowanie mojego self?.array.
Rostyslav Druzhchenko
4

Pozostałe odpowiedzi są w porządku, chociaż szukałem sposobu na uzyskanie adresu wskaźnika jako liczby całkowitej:

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

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

Tylko mała kontynuacja.

Charlie Monroe
źródło
Poniżej znajduje się wersja tej odpowiedzi dla Swift 3.
RenniePet
3

Odpowiedzi @Drew można użyć tylko dla typu klasy.
Odpowiedź @nschum może dotyczyć tylko typu struktury.

Jeśli jednak używasz drugiej metody, aby uzyskać adres tablicy z elementem typu wartości. Swift skopiuje całą tablicę, ponieważ w Swift tablica jest kopiowana przy zapisie i Swift nie może upewnić się, że zachowa się w ten sposób po przekazaniu kontroli do C / C ++ (co jest wyzwalane przez użycie &do uzyskania adresu). A jeśli zamiast tego użyjesz pierwszej metody, zostanie ona automatycznie przekonwertowana Arrayna NSArraycoś, czego z pewnością nie chcemy.

Najprostszym i najbardziej ujednoliconym sposobem, jaki znalazłem, jest użycie instrukcji lldb frame variable -L yourVariableName.

Lub możesz połączyć ich odpowiedzi:

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
źródło
3

To jest dla Swift 3.

Podobnie jak @CharlieMonroe, chciałem uzyskać adres jako liczbę całkowitą. W szczególności chciałem, aby adres obiektu Thread był używany jako identyfikator wątku w module rejestrowania diagnostycznego w sytuacjach, w których nazwa wątku nie była dostępna.

W oparciu o kod Charliego Monroe, oto co wymyśliłem do tej pory. Ale uwaga, jestem nowy w Swift, to może nie być poprawne ...

  // 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

Ostatnia instrukcja jest tam, ponieważ bez niej otrzymywałem adresy takie jak 0x60000007DB3F. Operacja modulo w ostatniej instrukcji konwertuje to na 0x7DB3F.

RenniePet
źródło
3

Moje rozwiązanie w Swift 3

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

ten kod tworzy opis jak domyślny opis <MyClass: 0x610000223340>

EvGeniy ​​Ilyin
źródło
2

Z pewnością nie jest to najszybszy ani najbezpieczniejszy sposób. Ale to działa dla mnie. Pozwoli to każdej podklasie nsobject na przyjęcie tej właściwości.

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
źródło
dzięki za informację zwrotną Jeff, zaktualizuję odpowiedź
Charlton Provatas
1
Nieważne! To był mój błąd! Twój kod działa dobrze z czystą klasą Swift. Przepraszam za błąd.
Jeff,