Impression d'une adresse mémoire variable dans Swift

166

Est-il possible de simuler le [NSString stringWithFormat:@"%p", myVar], à partir d'Objective-C, dans le nouveau langage Swift?

Par exemple:

let str = "A String"
println(" str value \(str) has address: ?")
apouche
la source
2
Dans [NSString stringWithFormat:@"%p", myVar], myVardoit être un pointeur. Dans votre code Swift, ce strn'est pas un pointeur. La comparaison ne s'applique donc pas.
user102008
5
Il convient de noter que, du moins lorsque je tape ceci, les deux commentaires ci-dessus sont incorrects.
Ben Leggiero

Réponses:

112

Swift 2

Ce fait maintenant partie de la bibliothèque standard: 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

Swift 3

Pour Swift 3, utilisez withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}
A dessiné
la source
2
unsafeAddressOf () ne fonctionne que pour les types de classe (comme @Nick le souligne ci-dessous). Ainsi, cette réponse ne fonctionne que si Foundation est importé et que String est ponté vers NSString. En Swift brut, String est un type valeur et unsafeAddressOf ne peut pas être utilisé pour prendre son adresse (la tentative entraîne une erreur de compilation).
Stephen Schaub
29
Que faire si je souhaite imprimer une adresse de valeur immuable avec Swift 3? withUnsafePointerentraîne une cannot pass immutable value as inout argumenterreur.
Alexander Vasenin
12
Même si c'est la réponse acceptée et la plus votée, elle donne toujours de mauvais résultats. Exemple: print(self.description)impressions <MyViewController: 0x101c1d580>, nous l'utilisons comme référence. var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }imprime 0x16fde4028qui est une adresse clairement différente. Quelqu'un peut-il expliquer pourquoi?
Alexander Vasenin
4
BTW, cela s'imprime 0x101c1d580comme prévu:print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
Alexander Vasenin
8
@nyg Votre réponse m'a donné un indice sur la cause réelle de l'erreur: UnsafePointerest une structure, donc pour imprimer l'adresse vers laquelle elle pointe (et non la structure elle-même), vous devez imprimer String(format: "%p", $0.pointee)!
Alexander Vasenin
214

Remarque: Ceci est pour les types de référence.

Swift 4/5:

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

Imprime l'adresse mémoire de someVar. (merci à @Ying)


Swift 3.1:

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

Imprime l'adresse mémoire de someVar.


Woodstock
la source
2
La correction automatique Xcode 8.2.1 me dit que c'est maintenantprint(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Jeff
2
Cela ne serait-il pas vrai uniquement si le someVar est un objet. Si someVar est un type valeur tel qu'une structure, cela donnera une adresse différente à chaque exécution.
OutOnAWeekend
3
@OutOnAWeekend Vous avez raison, probablement parce que la structure est copiée lorsqu'elle est passée en argument. En utilisant Unmanagedcela peut être fait comme ceci: print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque()).
nyg
1
À partir de Swift 4, j'ai également pu imprimer cette incantation - Unmanaged.passUnretained(someVar).toOpaque()(pas besoin de spécification générique)
Ying
2
La réponse Swift 4 est parfaite. Si vous souhaitez également obtenir la représentation sous forme de chaîne sans impression, je vous recommande d'ajouter debugDescriptionà la fin de celle-ci.
Patrick
51

Notez que cette réponse était assez ancienne. Bon nombre des méthodes qu'il décrit ne fonctionnent plus. Plus précisément, .coreil n'est plus accessible.

Cependant, la réponse de @ drew est correcte et simple:

Cela fait maintenant partie de la bibliothèque standard: unsafeAddressOf.

La réponse à vos questions est donc:

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

Voici la réponse originale qui a été marquée correcte (pour la postérité / politesse):

Swift "cache" les pointeurs, mais ils existent toujours sous le capot. (parce que le runtime en a besoin, et pour des raisons de compatibilité avec Objc et C)

Il y a peu de choses à savoir cependant, mais d'abord comment imprimer l'adresse mémoire d'une Swift String?

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

Cela imprime l'adresse mémoire de la chaîne, si vous ouvrez XCode -> Debug Workflow -> Afficher la mémoire et allez à l'adresse imprimée, vous verrez les données brutes de la chaîne. Puisqu'il s'agit d'un littéral de chaîne, il s'agit d'une adresse mémoire à l'intérieur du stockage du binaire (pas de pile ou de tas).

Cependant, si vous faites

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

    // example printed address 0x103f30020

Ce sera sur la pile, car la chaîne est créée au moment de l'exécution

REMARQUE: .core._baseAddress n'est pas documenté, je l'ai trouvé à la recherche dans l'inspecteur de variables, et il peut être caché à l'avenir

_baseAddress n'est pas disponible sur tous les types, voici un autre exemple avec un CInt

    var testNumber : CInt = 289
    takesInt(&testNumber)

takesIntest une fonction d'assistance C comme celle-ci

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

Du côté Swift, cette fonction est takesInt(intptr: CMutablePointer<CInt>), donc elle prend un CMutablePointer vers un CInt, et vous pouvez l'obtenir avec & varname

La fonction imprime 0x7fff5fbfed98, à cette adresse mémoire, vous trouverez 289 (en notation hexadécimale). Vous pouvez modifier son contenu avec*intptr = 123456

Maintenant, quelques autres choses à savoir.

La chaîne, en swift, est un type primitif, pas un objet.
CInt est un type Swift mappé sur le type C int.
Si vous voulez l'adresse mémoire d'un objet, vous devez faire quelque chose de différent.
Swift a quelques types de pointeurs qui peuvent être utilisés lors de l'interaction avec C, et vous pouvez en savoir plus ici: Types de pointeurs Swift
De plus, vous pouvez en savoir plus sur eux en explorant leur déclaration (cmd + cliquez sur le type), pour comprendre comment convertir un type de pointeur vers un autre

    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 est une fonction d'assistance C que j'ai créée, avec cette implémentation

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

Encore une fois, un exemple d'adresse imprimée:, 0x6000000530b0et si vous passez par l'inspecteur de mémoire, vous trouverez votre NSString

Une chose que vous pouvez faire avec des pointeurs dans Swift (cela peut même être fait avec des paramètres inout)

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

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

Ou, interagir avec 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
la source
oui, le pointeur doit quitter mais pas seulement pour des raisons de compatibilité comme vous l'avez mentionné. les pointeurs habituellement utilisés par le système d'exploitation. même si le langage est un langage de haut niveau, les pointeurs doivent exister dans n'importe quelle langue à tout moment dans le moteur du système d'exploitation.
holex
J'ai dit "pour des raisons de compatibilité ET parce que le runtime en a besoin" :-) la deuxième déclaration récapitule ce que vous dites (je suppose qu'un programmeur le sait et le comprend, alors j'ai passé quelques mots)
LombaX
Je suppose que cela ne s'applique plus?
aleclarson le
Oui. J'ai modifié la bonne réponse de @Drew.
Rog
@LombaX nous ne pouvons imprimer qu'une adresse de type de référence? Puis-je imprimer l'adresse des variables?
AbhimanyuAryan
21

Pour obtenir l'adresse (de tas) d'un objet

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

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

( Edit: Swift 1.2 inclut désormais une fonction similaire appelée unsafeAddressOf.)

En Objective-C, ce serait [NSString stringWithFormat:@"%p", o].

oest une référence à l'instance. Donc, si oest affecté à une autre variable o2, l'adresse renvoyée pour o2sera la même.

Cela ne s'applique pas aux structures (y compris String) et aux types primitifs (comme Int), car ceux-ci vivent directement sur la pile. Mais nous pouvons récupérer l'emplacement sur la pile.

Pour obtenir l'adresse (de pile) d'une structure, d'un type intégré ou d'une référence d'objet

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

En Objective-C, ce serait [NSString stringWithFormat:@"%p", &o]ou [NSString stringWithFormat:@"%p", &i].

sest struct. Donc, si sest affecté à une autre variable s2, la valeur sera copiée et l'adresse renvoyée pour s2sera différente.

Comment ça s'emboîte (récapitulatif du pointeur)

Comme dans Objective-C, deux adresses différentes sont associées à o. Le premier est l'emplacement de l'objet, le second est l'emplacement de la référence (ou du pointeur) vers l'objet.

Oui, cela signifie que le contenu de l'adresse 0x7fff5fbfe658 est le numéro 0x6100000011d0 comme le débogueur peut nous le dire:

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

Donc, à l'exception des chaînes qui sont des structures, en interne, tout fonctionne à peu près de la même manière que dans (Objective-) C.

(À jour à partir de Xcode 6.3)

nschum
la source
Hmm. L'obtention de l'adresse de pile de la propriété d'un objet n'est pas cohérente. Des idées? Découvrez cet essentiel!
aleclarson le
Les propriétés de l'objet se trouvent sur le tas, pas sur la pile. Lorsque vous passez la propriété d'une instance de classe en tant que UnsafePointer, Swift copie en fait la valeur en premier et vous obtenez l'adresse de la copie. Je soupçonne que c'est pour empêcher le code C de contourner l'interface de l'objet et de provoquer un état incohérent. Je ne sais pas s'il existe un moyen de contourner cela.
nschum
Voici un fil de discussion que j'ai créé sur les forums des développeurs Apple . Quelques bonnes réponses là-dedans.
aleclarson le
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
*/

( Gist )


Dans Swift, nous traitons soit des types valeur (structures), soit des types référence (classes). En faisant:

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

Une partie de la mémoire est allouée à l'adresse X, et à cette adresse nous trouverons la valeur 42. Faire &ncrée un pointeur pointant vers l'adresse X, donc &nnous indique où nse trouve.

(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

En faisant:

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

La mémoire est allouée à deux endroits:

  • à l'adresse Y où se trouvent les données d'instance de classe et
  • à l'adresse X où se trouve la référence d'instance de classe.

Comme dit, les classes sont des types de référence: donc la valeur de cest située à l'adresse X, à laquelle nous trouverons la valeur de Y. Et à l'adresse Y + 16 nous trouverons fooet à l'adresse Y + 24 nous trouverons bar( à + 0 et + 8, nous trouverons des données de type et des nombres de références, je ne peux pas vous en dire beaucoup plus à ce sujet ...).

(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

0x2avaut 42 (foo) et 0x5484 (bar).

Dans les deux cas, utiliser &nou &cnous donnera l'adresse X. Pour les types valeur, c'est ce que nous voulons, mais pas pour les types référence.

En faisant:

let referencePointer = UnsafeMutablePointer<C>(&c)

Nous créons un pointeur sur la référence, c'est-à-dire un pointeur qui pointe vers l'adresse X. Même chose lors de l'utilisation 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)

Maintenant que nous avons une meilleure compréhension de ce qui se passe sous le capot, et que nous maintenant qu'à l'adresse X nous trouverons l'adresse Y (qui est celle que nous voulons), nous pouvons faire ce qui suit pour l'obtenir:

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

Vérification:

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

Il existe d'autres moyens de procéder:

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

toOpaque()appelle réellement unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

J'espère que cela a aidé ... cela m'a aidé 😆.

nyg
la source
Je viens de remarquer que tout en essayant d'imprimer l'adresse de la même structure à travers 2 instances différentes de MemoryLocationproduit 2 adresses différentes.
user1046037
@ user1046037 Merci, fait le changement pour la classe init. J'obtiens également deux adresses différentes, mais uniquement lorsque j'utilise une structure vide. Utiliser une structure vide me donne toujours des résultats étranges. Je suppose que le compilateur fait quelques optimisations ...
nyg
@ user1046037 Vérifiez: pastebin.com/mpd3ujw2 . Apparemment, toutes les structures vides pointent vers la même adresse mémoire. Cependant, quand on veut stocker le pointeur dans une variable il va en créer une copie (ou de la struct?) ...
nyg
C'est intéressant, mais une fois imprimé deux fois, il imprime les différentes adresses mémoire. Il en va de même pour les réponses ci-dessus.
user1046037
@ user1046037 Je ne suis pas sûr de comprendre ce que vous voulez dire, avez-vous du code? (J'ai toujours la même adresse mémoire)
nyg
15

Types de référence:

  • Il est logique d'obtenir l'adresse mémoire d'un type de référence car elle représente l'identité.
  • === L'opérateur d'identité est utilisé pour vérifier que 2 objets pointent vers la même référence.
  • Utilisez ObjectIdentifierpour obtenir l'adresse mémoire

Code:

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

Types de valeur:

  • La nécessité d'obtenir l'adresse mémoire d'un type valeur n'a pas beaucoup d'importance (car il s'agit d'une valeur) et l'accent serait davantage mis sur l'égalité de la valeur.
utilisateur1046037
la source
12

Utilisez simplement ceci:

print(String(format: "%p", object))
Pavelcauselov
la source
Si vous recevez une plainte du compilateur concernant " MyClass?" n'est pas conforme à CVarArg, vous pouvez le faire extension Optional : CVarArg { }. Sinon, cela semble imprimer des adresses sans toute la folie «non sûre» des autres réponses.
Devin Lane
Il nécessite la mise en œuvre de var _cVarArgEncoding: [Int]on CVarArg. Pas clair comment cela devrait être mis en œuvre.
Yuchen Zhong le
10

Si vous voulez juste voir cela dans le débogueur et ne rien faire d'autre avec lui, il n'est pas nécessaire d'obtenir le Intpointeur. Pour obtenir la représentation sous forme de chaîne de l'adresse d'un objet en mémoire, utilisez simplement quelque chose comme ceci:

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

Exemple d'utilisation:

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

De plus, rappelez- vous que vous pouvez simplement imprimer un objet sans le remplacer description, et il affichera son adresse de pointeur à côté d'un texte plus descriptif (si souvent cryptique).

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
la source
1
Veuillez accompagner les votes négatifs avec un commentaire expliquant pourquoi, donc moi et toute autre personne qui vient ici sait pourquoi c'est une mauvaise solution :)
Ben Leggiero
1
Simple et soigné!
badhanganesh
9

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

Usage:

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

print("nil: \(String.pointer(nil))")
// nil: nil
neoneye
la source
Cette réponse est incorrecte. Si vous créez deux instances de la même classe, la même adresse mémoire sera renvoyée pour les deux instances. Unmanaged.passUnretained(myObject).toOpaque()fonctionne correctement à la place.
Padraig
@Padraig Merci, j'ai mis à jour votre code. Malheureusement, cela prend maintenant un AnyObjectparamètre. Je préférerais Anycomme type d'entrée.
neoneye
6

Dans Swift4 à propos de 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
la source
1
m'a sauvé la journée. Il devrait y avoir un badge "l'acquisition récente la plus utile"
Anton Tropashko
En effet, c'est la seule approche qui a imprimé mon self?.array.
Rostyslav Druzhchenko
4

Les autres réponses sont correctes, même si je cherchais un moyen d'obtenir l'adresse du pointeur sous forme d'entier:

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

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

Juste un petit suivi.

Charlie Monroe
la source
Voir ci-dessous pour une version de cette réponse pour Swift 3.
RenniePet
3

La réponse fournie par @Drew ne peut être utilisée que pour le type de classe.
La réponse fournie par @nschum ne peut être que pour le type struct.

Cependant, si vous utilisez la deuxième méthode pour obtenir l'adresse d'un tableau avec un élément de type valeur. Swift copiera tout le tableau car dans Swift, le tableau est une copie sur écriture et Swift ne peut pas s'assurer qu'il se comporte de cette façon une fois qu'il passe le contrôle à C / C ++ (qui est déclenché en utilisant &pour obtenir l'adresse). Et si vous utilisez la première méthode à la place, elle sera automatiquement convertie Arrayen NSArrayce que nous ne voulons sûrement pas.

Donc, le moyen le plus simple et le plus unifié que j'ai trouvé est d'utiliser l'instruction lldb frame variable -L yourVariableName.

Ou vous pouvez combiner leurs réponses:

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
la source
3

Ceci est pour Swift 3.

Comme @CharlieMonroe, je voulais obtenir l'adresse sous forme d'entier. Plus précisément, je voulais que l'adresse d'un objet Thread soit utilisée comme ID de thread dans un module de journalisation de diagnostic, pour les situations où aucun nom de thread n'était disponible.

Basé sur le code de Charlie Monroe, voici ce que j'ai trouvé jusqu'ici. Mais attention, je suis très nouveau sur Swift, ce n'est peut-être pas correct ...

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

La dernière déclaration est là parce que sans elle, j'obtenais des adresses comme 0x60000007DB3F. L'opération modulo dans la dernière instruction convertit cela en 0x7DB3F.

RenniePet
la source
3

Ma solution sur Swift 3

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

ce code crée une description comme la description par défaut <MyClass: 0x610000223340>

EvGeniy ​​Ilyin
la source
2

Ce n'est certainement pas le moyen le plus rapide ou le plus sûr de s'y prendre. Mais cela fonctionne pour moi. Cela permettra à toute sous-classe nsobject d'adopter cette propriété.

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
la source
merci pour les commentaires Jeff, je mettrai à jour la réponse
Charlton Provatas
1
Ça ne fait rien! C'etait mon erreur! Votre code fonctionne bien avec une classe Swift pure. Désolé pour l'erreur.
Jeff