Schnelles Drucken einer variablen Speicheradresse

165

Gibt es überhaupt eine Möglichkeit, das [NSString stringWithFormat:@"%p", myVar]von Objective-C in der neuen Swift-Sprache zu simulieren ?

Beispielsweise:

let str = "A String"
println(" str value \(str) has address: ?")
Apouche
quelle
2
In [NSString stringWithFormat:@"%p", myVar], myVarmuss ein Zeiger sein. Ist in Ihrem Swift-Code strkein Zeiger. Der Vergleich trifft also nicht zu.
user102008
5
Es ist erwähnenswert, dass zumindest wenn ich dies schreibe, die beiden obigen Kommentare falsch sind.
Ben Leggiero

Antworten:

112

Swift 2

Dies ist jetzt Teil der Standardbibliothek : 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

Verwenden Sie für Swift 3 withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \($0)")
}
Drew
quelle
2
unsafeAddressOf () funktioniert nur für Klassentypen (wie @Nick unten ausführt). Daher funktioniert diese Antwort nur, wenn Foundation importiert und String mit NSString verbunden wird. In einfachem Swift ist String ein Werttyp und unsafeAddressOf kann nicht verwendet werden, um seine Adresse zu übernehmen (der Versuch führt zu einem Kompilierungsfehler).
Stephen Schaub
29
Was ist, wenn ich mit Swift 3 eine Adresse von unveränderlichem Wert drucken möchte ? withUnsafePointerführt zu einem cannot pass immutable value as inout argumentFehler.
Alexander Vasenin
12
Obwohl es akzeptiert und die Antwort mit der höchsten Bewertung ist, gibt es immer noch falsche Ergebnisse. Beispiel: print(self.description)Drucke <MyViewController: 0x101c1d580>, wir verwenden es als Referenz. var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }druckt 0x16fde4028die deutlich andere Adresse. Kann jemand erklären warum?
Alexander Vasenin
4
0x101c1d580print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
Übrigens
8
@nyg Ihre Antwort gab mir einen Hinweis auf die eigentliche Fehlerursache: UnsafePointerist eine Struktur. Um also die Adresse zu drucken, auf die sie zeigt (und nicht die Struktur selbst), müssen Sie drucken String(format: "%p", $0.pointee)!
Alexander Vasenin
213

Hinweis: Dies gilt für Referenztypen.

Swift 4/5:

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

Druckt die Speicheradresse von someVar. (danke an @Ying)


Swift 3.1:

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

Druckt die Speicheradresse von someVar.


Holzlager
quelle
2
Xcode 8.2.1 Autokorrektur sagt mir, dass es jetzt istprint(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Jeff
2
Wäre das nicht nur wahr, wenn someVar ein Objekt ist? Wenn someVar zufällig ein Werttyp wie eine Struktur ist, wird bei jeder Ausführung eine andere Adresse angegeben.
OutOnAWeekend
3
@OutOnAWeekend Sie haben Recht, höchstwahrscheinlich, weil die Struktur kopiert wird, wenn sie als Argument übergeben wird. Die Verwendung Unmanagedkann folgendermaßen erfolgen : print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque()).
Nyg
1
Ab Swift 4 konnte ich diese Beschwörung auch zum Drucken bringen - Unmanaged.passUnretained(someVar).toOpaque()(keine generische Spezifikation erforderlich)
Ying
2
Die Swift 4 Antwort ist perfekt. Wenn Sie die Zeichenfolgendarstellung auch ohne Drucken erhalten möchten, würde ich empfehlen, debugDescriptionsie am Ende hinzuzufügen .
Patrick
51

Beachten Sie, dass diese Antwort ziemlich alt war. Viele der beschriebenen Methoden funktionieren nicht mehr. Speziell.core kann nicht mehr zugegriffen werden.

Die Antwort von @ draw ist jedoch richtig und einfach:

Dies ist jetzt Teil der Standardbibliothek: unsafeAddressOf.

Die Antwort auf Ihre Fragen lautet also:

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

Hier ist die ursprüngliche Antwort, die als richtig markiert wurde (für Nachwelt / Höflichkeit):

Schnelle "versteckt" Zeiger, aber sie existieren immer noch unter der Haube. (weil die Laufzeit es braucht und aus Kompatibilitätsgründen mit Objc und C)

Es gibt jedoch einige Dinge zu wissen, aber zuerst, wie man die Speicheradresse eines Swift-Strings druckt?

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

Dadurch wird die Speicheradresse der Zeichenfolge gedruckt. Wenn Sie XCode -> Debug-Workflow -> Speicher anzeigen öffnen und zur gedruckten Adresse wechseln, werden die Rohdaten der Zeichenfolge angezeigt. Da dies ein String-Literal ist, ist dies eine Speicheradresse im Speicher der Binärdatei (nicht Stapel oder Heap).

Wenn Sie dies jedoch tun

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

    // example printed address 0x103f30020

Dies befindet sich auf dem Stapel, da die Zeichenfolge zur Laufzeit erstellt wird

HINWEIS: .core._baseAddress ist nicht dokumentiert. Ich habe festgestellt, dass es im Variableninspektor angezeigt wird und möglicherweise in Zukunft ausgeblendet wird

_baseAddress ist nicht für alle Typen verfügbar, hier ein weiteres Beispiel mit einem CInt

    var testNumber : CInt = 289
    takesInt(&testNumber)

Wo takesIntist eine C-Helferfunktion wie diese?

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

Auf der Swift-Seite ist diese Funktion so takesInt(intptr: CMutablePointer<CInt>), dass ein CMutablePointer zu einem CInt führt und Sie ihn mit & varname erhalten können

Die Funktion wird gedruckt 0x7fff5fbfed98 , und an dieser Speicheradresse finden Sie 289 (in hexadezimaler Schreibweise). Sie können den Inhalt mit ändern*intptr = 123456

Nun noch ein paar andere Dinge zu wissen.

String ist schnell ein primitiver Typ, kein Objekt.
CInt ist ein Swift-Typ, der dem C int-Typ zugeordnet ist.
Wenn Sie die Speicheradresse eines Objekts möchten, müssen Sie etwas anderes tun.
Swift verfügt über einige Zeigertypen, die bei der Interaktion mit C verwendet werden können. Weitere Informationen hierzu finden Sie hier: Swift-Zeigertypen
Darüber hinaus erfahren Sie mehr darüber, wie sie ihre Deklaration untersuchen (cmd + Klicken Sie auf den Typ), um zu verstehen, wie sie konvertiert werden eine Art Zeiger in eine andere

    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 ist eine C-Hilfsfunktion, die ich mit dieser Implementierung erstellt habe

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

Wieder ein Beispiel für die gedruckte Adresse: 0x6000000530b0 und wenn Sie den Speicherinspektor durchlaufen, finden Sie Ihren NSString

Eine Sache, die Sie mit Zeigern in Swift machen können (dies kann sogar mit inout-Parametern gemacht werden)

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

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

Oder mit Objc / c interagieren

// 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
quelle
Ja, der Zeiger muss beendet werden, aber nicht nur aus Kompatibilitätsgründen, wie Sie angegeben haben. die Zeiger, die normalerweise vom Betriebssystem verwendet werden. Selbst wenn es sich bei der Sprache um eine Hochsprache handelt, müssen die Zeiger jederzeit in einer beliebigen Sprache in der Engine des Betriebssystems vorhanden sein.
Holex
Ich sagte "aus Kompatibilitätsgründen UND weil die Laufzeit es braucht" :-) Die zweite Anweisung fasst zusammen, was Sie sagen (ich
gehe
Ich nehme an, das trifft nicht mehr zu?
Aleclarson
Ja. Ich habe die richtige Antwort von @Drew darin bearbeitet.
Rog
@LombaX können wir nur Adresse des Referenztyps drucken? Kann ich die Adresse von Variablen nicht drucken?
AbhimanyuAryan
21

Um die (Heap-) Adresse eines Objekts abzurufen

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

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

( Bearbeiten: Swift 1.2 enthält jetzt eine ähnliche Funktion namensunsafeAddressOf .)

In Objective-C wäre dies [NSString stringWithFormat:@"%p", o].

oist ein Verweis auf die Instanz. Wenn oalso eine andere Variable zugewiesen ist o2, ist die zurückgegebene Adresse für o2dieselbe.

Dies gilt nicht für Strukturen (einschließlich String) und primitive Typen (wie Int), da diese direkt auf dem Stapel leben. Wir können jedoch den Speicherort auf dem Stapel abrufen.

Um die (Stapel-) Adresse einer Struktur, eines eingebauten Typs oder einer Objektreferenz abzurufen

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

In Objective-C wäre dies [NSString stringWithFormat:@"%p", &o]oder [NSString stringWithFormat:@"%p", &i].

sist struct. Wenn salso eine andere Variable zugewiesen wird s2, wird der Wert kopiert und die zurückgegebene Adresse für s2ist unterschiedlich.

Wie es zusammenpasst (Zeigerrückblick)

Wie in Objective-C sind zwei verschiedene Adressen zugeordnet o . Der erste ist der Ort des Objekts, der zweite ist der Ort der Referenz (oder des Zeigers) auf das Objekt.

Ja, dies bedeutet, dass der Inhalt der Adresse 0x7fff5fbfe658 die Nummer 0x6100000011d0 ist, wie der Debugger uns mitteilen kann:

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

Abgesehen davon, dass Strings Strukturen sind, funktioniert dies intern ziemlich genau so wie in (Objective-) C.

(Stand Xcode 6.3)

nschum
quelle
Hmm. Das Abrufen der Stapeladresse der Eigenschaft eines Objekts ist nicht konsistent. Irgendwelche Ideen? Schauen Sie sich dieses Wesentliche an!
Aleclarson
Die Objekteigenschaften befinden sich auf dem Heap und nicht auf dem Stapel. Wenn Sie die Eigenschaft einer Klasseninstanz als UnsafePointer übergeben, kopiert Swift den Wert zuerst und Sie erhalten die Adresse der Kopie. Ich vermute, das soll verhindern, dass C-Code die Schnittstelle des Objekts umgeht und einen inkonsistenten Zustand verursacht. Ich weiß nicht, ob es einen Weg gibt, das zu umgehen.
Nschum
Hier ist ein Thread, den ich in den Apple Developer Forums erstellt habe . Einige gute Antworten.
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
*/

( Kern )


In Swift beschäftigen wir uns entweder mit Werttypen (Strukturen) oder Referenztypen (Klassen). Wenn Sie:

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

An der Adresse X wird etwas Speicher zugewiesen, und an dieser Adresse finden wir den Wert 42. Wenn Sie dies tun, &nwird ein Zeiger erstellt, der auf die Adresse X zeigt, und es &nwird uns mitgeteilt, wo nsich dieser befindet.

(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

Wenn Sie:

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

Der Speicher wird an zwei Stellen zugewiesen:

  • an der Adresse Y, an der sich die Klasseninstanzdaten befinden, und
  • an der Adresse X, an der sich die Klasseninstanzreferenz befindet.

Wie gesagt, Klassen sind Referenztypen: Der Wert von cbefindet sich also an der Adresse X, an der wir den Wert von Y finden. Und an der Adresse Y + 16 finden wir foound an der Adresse Y + 24 finden wir bar( Bei + 0 und + 8 finden wir Typdaten und Referenzzählungen. Mehr kann ich dazu nicht sagen ...).

(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

0x2a ist 42 (foo) und 0x54 ist 84 (bar).

In beiden Fällen mit &noder&c wir geben uns die Adresse X. Für Werttypen ist dies das, was wir wollen, aber nicht für Referenztypen.

Wenn Sie:

let referencePointer = UnsafeMutablePointer<C>(&c)

Wir erstellen einen Zeiger auf die Referenz, dh einen Zeiger, der auf die Adresse X zeigt. Dasselbe gilt bei der Verwendung 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)

Jetzt, da wir besser verstehen, was unter der Haube vor sich geht, und jetzt, wo wir unter Adresse X die Adresse Y finden (die wir wollen), können wir Folgendes tun, um sie zu erhalten:

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

Überprüfen:

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

Es gibt andere Möglichkeiten, dies zu tun:

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

toOpaque()ruft tatsächlich an unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

Ich hoffe das hat geholfen ... es hat mir geholfen 😆.

nyg
quelle
Ich habe gerade bemerkt, dass beim Versuch, die Adresse derselben Struktur über 2 verschiedene Instanzen von zu drucken, MemoryLocation2 verschiedene Adressen erzeugt werden.
user1046037
@ user1046037 Danke, habe die Änderung für die Klasse init vorgenommen. Ich bekomme auch zwei verschiedene Adressen, aber nur, wenn ich eine leere Struktur verwende. Die Verwendung einer leeren Struktur führt immer zu seltsamen Ergebnissen. Ich vermute, der Compiler nimmt einige Optimierungen vor ...
Nyg
@ user1046037 Überprüfen Sie: pastebin.com/mpd3ujw2 . Anscheinend zeigen alle leeren Strukturen auf dieselbe Speicheradresse. Wenn wir jedoch den Zeiger in einer Variablen speichern möchten, wird eine Kopie davon (oder der Struktur?)
Erstellt
Das ist interessant, aber wenn es zweimal gedruckt wird, werden die verschiedenen Speicheradressen gedruckt. Gleiches gilt auch für die obigen Antworten.
user1046037
@ user1046037 Ich bin nicht sicher, ob ich verstehe, was du meinst. Hast du Code? (Ich bekomme immer die gleiche Speicheradresse)
Nyg
15

Referenztypen:

  • Es ist sinnvoll, die Speicheradresse eines Referenztyps abzurufen, da diese die Identität darstellt.
  • === Der Identitätsoperator wird verwendet, um zu überprüfen, ob 2 Objekte auf dieselbe Referenz verweisen.
  • Verwenden Sie ObjectIdentifierdiese Option , um die Speicheradresse abzurufen

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

Werttypen:

  • Die Notwendigkeit, die Speicheradresse eines Wertetyps abzurufen, ist nicht von großer Bedeutung (da es sich um einen Wert handelt), und der Schwerpunkt würde eher auf der Gleichheit des Werts liegen.
user1046037
quelle
12

Verwenden Sie einfach dies:

print(String(format: "%p", object))
pavelcauselov
quelle
Wenn Sie eine Compiler-Beschwerde erhalten, dass " MyClass?" nicht mit CVarArg übereinstimmt, können Sie dies tun extension Optional : CVarArg { }. Andernfalls scheint dies Adressen zu drucken, ohne den "unsicheren" Wahnsinn der anderen Antworten.
Devin Lane
Es erfordert die Implementierung von var _cVarArgEncoding: [Int] on CVarArg. Nicht klar, wie das umgesetzt werden soll.
Yuchen Zhong
10

Wenn Sie dies nur im Debugger sehen und nichts anderes damit tun möchten, müssen Sie den IntZeiger nicht tatsächlich abrufen. Verwenden Sie Folgendes, um die Zeichenfolgendarstellung der Adresse eines Objekts im Speicher abzurufen:

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

Anwendungsbeispiel:

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

Denken Sie außerdem daran, dass Sie ein Objekt einfach drucken können, ohne es zu überschreiben description, und dass seine Zeigeradresse neben aussagekräftigerem (wenn auch häufig kryptischem) Text angezeigt wird.

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
quelle
1
Bitte begleiten Sie alle Abstimmungen mit einem Kommentar, der erklärt, warum, damit ich und alle anderen, die hierher kommen, wissen, warum dies eine schlechte Lösung ist :)
Ben Leggiero
1
Einfach und ordentlich!
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)
    }
}

Verwendung:

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

print("nil: \(String.pointer(nil))")
// nil: nil
neoneye
quelle
Diese Antwort ist falsch. Wenn Sie zwei Instanzen derselben Klasse erstellen, wird für beide Instanzen dieselbe Speicheradresse zurückgegeben. Unmanaged.passUnretained(myObject).toOpaque()funktioniert stattdessen richtig.
Padraig
@ Padraig Danke, ich habe mit deinem Code aktualisiert. Leider braucht es jetzt einen AnyObjectParameter. Ich würde Anyals Eingabetyp bevorzugen .
Neoneye
6

In Swift4 über 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
quelle
1
hat meinen Tag gerettet. Es sollte ein Abzeichen geben "die nützlichste jüngste so Erwerb"
Anton Tropashko
In der Tat ist dies der einzige Ansatz, der meine gedruckt hat self?.array.
Rostyslav Druzhchenko
4

Die anderen Antworten sind in Ordnung, obwohl ich nach einer Möglichkeit gesucht habe, die Zeigeradresse als Ganzzahl zu erhalten:

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

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

Nur ein kleines Follow-up.

Charlie Monroe
quelle
Unten finden Sie eine Version dieser Antwort für Swift 3.
RenniePet
3

Die Antwort @Drew kann nur für den Klassentyp verwendet werden.
Die Antwort @nschum kann nur für den Strukturtyp sein.

Wenn Sie jedoch die zweite Methode verwenden, um die Adresse eines Arrays mit dem Werttypelement abzurufen. Swift kopiert das gesamte Array, da das Swift-Array beim Schreiben kopiert wird und Swift nicht sicherstellen kann, dass es sich so verhält, wenn es die Kontrolle an C / C ++ übergibt (was durch Abrufen &der Adresse ausgelöst wird ). Und wenn Sie stattdessen die erste Methode verwenden, wird diese automatisch konvertiert Array, NSArraywas wir sicherlich nicht wollen.

Der einfachste und einheitlichste Weg, den ich gefunden habe, ist die Verwendung von lldb-Anweisungen frame variable -L yourVariableName .

Oder Sie können ihre Antworten kombinieren:

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
quelle
3

Dies ist für Swift 3.

Wie bei @CharlieMonroe wollte ich die Adresse als Ganzzahl erhalten. Insbesondere wollte ich, dass die Adresse eines Thread-Objekts als Thread-ID in einem Diagnoseprotokollierungsmodul verwendet wird, wenn kein Thread-Name verfügbar ist.

Basierend auf Charlie Monroes Code habe ich mir Folgendes ausgedacht. Aber Vorsicht, ich bin sehr neu bei Swift, das ist möglicherweise nicht richtig ...

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

Die letzte Anweisung ist da, weil ich ohne sie Adressen wie 0x60000007DB3F bekommen habe. Die Modulo-Operation in der letzten Anweisung konvertiert diese in 0x7DB3F.

RenniePet
quelle
3

Meine Lösung für Swift 3

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

Dieser Code erstellt eine Beschreibung wie die Standardbeschreibung <MyClass: 0x610000223340>

EvGeniy ​​Ilyin
quelle
2

Dies ist sicherlich nicht der schnellste oder sicherste Weg, dies zu tun. Aber es funktioniert bei mir. Dadurch kann jede nsobject-Unterklasse diese Eigenschaft übernehmen.

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
quelle
Vielen Dank für das Feedback Jeff, ich werde die Antwort aktualisieren
Charlton Provatas
1
Keine Ursache! Es war mein Fehler! Ihr Code funktioniert gut mit einer reinen Swift-Klasse. Entschuldige mich für den Fehler.
Jeff