[NSString stringWithFormat:@"%p", myVar]
Objective-C'den yeni Swift dilinde simüle etmek için yine de var mı ?
Örneğin:
let str = "A String"
println(" str value \(str) has address: ?")
[NSString stringWithFormat:@"%p", myVar]
Objective-C'den yeni Swift dilinde simüle etmek için yine de var mı ?
Örneğin:
let str = "A String"
println(" str value \(str) has address: ?")
Yanıtlar:
Bu artık standart kütüphanenin parçasıdır: 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 için withUnsafePointer
şunları kullanın :
var str = "A String"
withUnsafePointer(to: &str) {
print(" str value \(str) has address: \($0)")
}
withUnsafePointer
sonuçlanır cannot pass immutable value as inout argument
.
print(self.description)
baskılar <MyViewController: 0x101c1d580>
, referans olarak kullanıyoruz. açıkça farklı bir adres olan var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }
baskılar 0x16fde4028
. Nedenini açıklayan var mı?
0x101c1d580
beklendiği gibi yazdırılıyor :print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
UnsafePointer
, bu yüzden işaret ettiği adresi yazdırmak için (yapının kendisini değil) yazdırmanız gerekir String(format: "%p", $0.pointee)
!
Not: Bu referans türleri içindir.
print(Unmanaged.passUnretained(someVar).toOpaque())
SomeVar'ın bellek adresini yazdırır. (@Ying sayesinde)
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
SomeVar'ın bellek adresini yazdırır.
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Unmanaged
böyle yapılabilir: print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque())
.
Unmanaged.passUnretained(someVar).toOpaque()
(jenerik spesifikasyona gerek yok)
debugDescription
, sonuna eklemenizi öneririm .
Bu cevabın oldukça eski olduğuna dikkat edin. Açıkladığı yöntemlerin çoğu artık çalışmıyor. Özel .core
olarak artık erişilemiyor.
Ancak @ drew'un cevabı doğru ve basittir:
Bu artık standart kütüphanenin bir parçası: unsafeAddressOf.
Yani sorularınızın cevabı:
println(" str value \(str) has address: \(unsafeAddressOf(str))")
Doğru olarak işaretlenmiş orijinal cevap (gelecek nesiller / nezaket için):
Swift işaretçileri "gizler", ancak yine de kaputun altında bulunurlar. (çünkü çalışma zamanının buna ihtiyacı olduğu ve Objc ve C ile uyumluluk nedeniyle)
Ancak bilmeniz gereken birkaç şey var, ancak önce bir Swift String'in bellek adresini nasıl yazdırabilirim?
var aString : String = "THIS IS A STRING"
NSLog("%p", aString.core._baseAddress) // _baseAddress is a COpaquePointer
// example printed address 0x100006db0
Bu, dizenin bellek adresini yazdırır, XCode -> Debug Workflow -> Belleği Görüntüle'yi açar ve yazdırılan adrese giderseniz, dizenin ham verilerini görürsünüz. Bu bir dize değişmez değeri olduğundan, bu ikili (depo veya yığın değil) depolama içindeki bir bellek adresidir.
Ancak, eğer
var aString : String = "THIS IS A STRING" + "This is another String"
NSLog("%p", aString.core._baseAddress)
// example printed address 0x103f30020
Dize çalışma zamanında oluşturulduğundan, bu yığın üzerinde olacaktır
NOT: .core._baseAddress belgelenmemiştir, değişken denetçiye bakarak buldum ve gelecekte gizli olabilir
_baseAddress tüm türlerde mevcut değildir, burada CInt ile başka bir örnek
var testNumber : CInt = 289
takesInt(&testNumber)
takesInt
Böyle bir C yardımcı işlevi nerede
void takesInt(int *intptr)
{
printf("%p", intptr);
}
Swift tarafında, bu işlev, bu takesInt(intptr: CMutablePointer<CInt>)
nedenle bir CMutablePointer bir CInt alır ve & varname ile elde edebilirsiniz
İşlev yazdırılır 0x7fff5fbfed98
, bu hafıza adresinde 289 bulacaksınız (onaltılık gösterimde). İçeriğini şununla değiştirebilirsiniz:*intptr = 123456
Şimdi, bilinmesi gereken başka şeyler var.
Dize, hızlı bir şekilde, bir nesne değil, ilkel bir türdür.
CInt, C int Tipine eşlenmiş bir Swift türüdür.
Bir nesnenin bellek adresini istiyorsanız, farklı bir şey yapmanız gerekir.
Swift, C ile etkileşime girerken kullanılabilecek bazı İşaretçi Türlerine sahiptir ve bunları burada okuyabilirsiniz: Swift İşaretçi Türleri
Ayrıca, nasıl dönüştürüleceğini anlamak için bildirimlerini (cmd + türünü tıklatma) keşfetme hakkında daha fazla bilgi edinebilirsiniz. diğerine bir tür işaretçi
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
bu uygulamayla oluşturduğum bir C yardımcı işlevidir
void printptr(void ** ptr)
{
printf("%p", *ptr);
}
Yine, yazdırılan adrese bir örnek: 0x6000000530b0
ve bellek denetçisinden geçerseniz NSString'inizi bulacaksınız
Swift'teki işaretçilerle yapabileceğiniz bir şey (bu, giriş parametreleriyle bile yapılabilir)
func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>)
{
stringa.memory = "String Updated";
}
var testString : NSString = "test string"
println(testString)
playWithPointer(&testString)
println(testString)
Veya Objc / c ile etkileşim
// 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
func address<T: AnyObject>(o: T) -> Int {
return unsafeBitCast(o, Int.self)
}
class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970
( Düzenle: Swift 1.2 artık benzer bir işlev içeriyor unsafeAddressOf
.)
Objective-C'de bu olurdu [NSString stringWithFormat:@"%p", o]
.
o
örneğe bir referanstır. Dolayısıyla o
, başka bir değişkene atanmışsa o2
, için döndürülen adres o2
aynı olacaktır.
Bu, yapılar (dahil String
) ve ilkel türler (gibi Int
) için geçerli değildir, çünkü bunlar doğrudan yığın üzerinde yaşar. Ancak yığındaki yeri alabiliriz.
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
Objective-C'de bu [NSString stringWithFormat:@"%p", &o]
veya olur [NSString stringWithFormat:@"%p", &i]
.
s
yapıdır. Bu nedenle s
, başka bir değişkene atanırsa s2
, değer kopyalanır ve döndürülen adres s2
farklı olur.
Objective-C gibi, ile ilişkili iki farklı adres vardır o
. Birincisi, nesnenin konumudur, ikincisi, nesneye yapılan referansın (veya işaretçinin) konumudur.
Evet, bu, 0x7fff5fbfe658 adresinin içeriğinin, hata ayıklayıcının bize söyleyebileceği gibi 0x6100000011d0 sayısı olduğu anlamına gelir:
(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0
Yani, dizeler yapı olmak dışında, dahili olarak bunların hepsi (Objective-) C ile aynı şekilde çalışır.
(Xcode 6.3 itibariyle geçerlidir)
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 )
Swift'te ya değer türleri (yapılar) ya da referans türleri (sınıflar) ile ilgileniyoruz. Yaparken:
let n = 42 // Int is a structure, i.e. value type
X adresinde bir miktar bellek ayrılır ve bu adreste 42 değerini buluruz. Bunu yapmak &n
X adresini işaret eden bir işaretçi oluşturur, bu nedenle &n
bize nerede bulunduğunu söyler n
.
(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
Yaparken:
class C { var foo = 42, bar = 84 }
var c = C()
Bellek iki yerde tahsis edilir:
Söylendiği gibi, sınıflar referans türleridir: yani değeri c
X adresinde bulunur, burada Y değerini buluruz. Ve Y + 16 adresinde bulacağızfoo
adresinde ve Y + 24 adresinde buluruz bar
( + 0 ve + 8'de tür verilerini ve referans sayılarını bulacağız, size bunun hakkında daha fazla bilgi veremem ...).
(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
42 (foo) ve 0x54
84 (bar) 'dır.
Her iki durumda da, &n
veya &c
adresini kullanmak bize X adresini verecektir. Değer türleri için istediğimiz budur, ancak referans türleri için değildir.
Yaparken:
let referencePointer = UnsafeMutablePointer<C>(&c)
Referans üzerinde bir işaretçi oluşturuyoruz, yani X adresini işaret eden bir işaretçi withUnsafePointer(&c) {}
. Kullanırken aynı şey .
(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)
Artık kaputun altında neler olup bittiğini daha iyi anladığımıza ve şimdi X adresinde Y adresini (istediğimiz adres) bulacağımızı anlamak için aşağıdakileri yapabiliriz:
let addressY = unsafeBitCast(c, to: Int.self)
Doğrulanıyor:
(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)
Bunu yapmanın başka yolları da var:
let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }
toOpaque()
aslında çağırır unsafeBitCast(c, to: UnsafeMutableRawPointer.self)
.
Umarım bu yardımcı olmuştur ... benim için yaptı 😆.
MemoryLocation
2 farklı adres ürettiğini fark ettim .
===
kimlik operatörü, aynı referansı işaret eden 2 nesnenin kontrol edilmesi için kullanılır.ObjectIdentifier
Bellek adresini almak içinclass 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
Sadece şunu kullanın:
print(String(format: "%p", object))
MyClass?
" ile CVarArg'a uymuyorsa, bunu yapabilirsiniz extension Optional : CVarArg { }
. Aksi halde bu, diğer cevapların "güvensiz" deliliği olmadan adresleri yazdırıyor gibi görünüyor.
var _cVarArgEncoding: [Int]
Tarihinde uygulanmasını gerektirir CVarArg
. Bunun nasıl uygulanması gerektiği net değil.
Bunu sadece hata ayıklayıcıda görmek ve onunla başka bir şey yapmak istemiyorsanız, Int
işaretçiyi gerçekten almanıza gerek yoktur . Bir nesnenin adresinin dize halinde temsilini almak için, sadece şöyle bir şey kullanın:
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)
}
}
Örnek kullanım:
print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...
Ayrıca, bir nesneyi geçersiz kılmadan kolayca yazdırabileceğinizidescription
ve daha açıklayıcı (genellikle şifreli ise) metnin yanında işaretçi adresini göstereceğini unutmayın.
print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...
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)
}
}
print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698
print("nil: \(String.pointer(nil))")
// nil: nil
Unmanaged.passUnretained(myObject).toOpaque()
yerine düzgün çalışıyor.
AnyObject
parametre alıyor. Any
Giriş türü olarak tercih ederim .
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)
}
self?.array
.
Ben tamsayı olarak işaretçi adresi almak için bir yol arıyordum diğer cevaplar, gayet iyi:
let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)
/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int
Sadece küçük bir takip.
@Drew'un sağladığı yanıt yalnızca sınıf türü için kullanılabilir.
@Nschum tarafından sağlanan yanıt yalnızca yapı türü için olabilir.
Ancak, değer türü öğesiyle bir dizinin adresini almak için ikinci yöntemi kullanırsanız. Swift, tüm diziyi kopyalayacaktır çünkü Swift dizisinde yazma üzerine kopyalama ve Swift, kontrolü C / C ++ 'a ( &
adres almak için kullanarak tetiklenir) geçtikten sonra bu şekilde davrandığından emin olamaz . Bunun yerine ilk yöntemi kullanırsanız, otomatik olarak dönüştürülecektir Array
, NSArray
ki bu kesinlikle istemediğimiz bir şeydir.
Bulduğum en basit ve birleşik yol lldb komutunu kullanmak frame variable -L yourVariableName
.
Veya cevaplarını birleştirebilirsiniz:
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
}
Bu Swift 3 için.
@CharlieMonroe gibi adresi bir tamsayı olarak almak istedim. Özellikle, bir iş parçacığı adının kullanılabilir olduğu durumlar için, tanılama günlüğü modülünde bir iş parçacığı kimliği olarak kullanmak için bir iş parçacığı nesnesinin adresini istedi.
Charlie Monroe'nun koduna dayanarak, şimdiye kadar bulduğum şey. Ama dikkat et, Swift için çok yeniyim, bu doğru olmayabilir ...
// 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
Son ifade orada çünkü o olmadan ben 0x60000007DB3F gibi adresler alıyordu. Son deyimdeki modulo işlemi bunu 0x7DB3F'ye dönüştürür.
Swift 3'teki çözümüm
extension MyClass: CustomStringConvertible {
var description: String {
return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
}
}
bu kod varsayılan açıklama gibi açıklama oluşturur
<MyClass: 0x610000223340>
Bu kesinlikle en hızlı ya da en güvenli yol değil. Ama benim için çalışıyor. Bu, herhangi bir nsobject alt sınıfının bu özelliği benimsemesine izin verecektir.
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
[NSString stringWithFormat:@"%p", myVar]
,myVar
bir işaretçi olmalıdır. Swift kodunuzda,str
bir işaretçi değildir. Dolayısıyla karşılaştırma geçerli değildir.