是否有任何方式来模拟[NSString stringWithFormat:@“%p”,myVar],从Objective-C,在新的Swift语言?

例如:

let str = "A String"
println(" str value \(str) has address: ?")

当前回答

请注意,这个答案是相当古老的。书中描述的许多方法已经不再有效。特别是不能再访问.core。

但是@drew的回答是正确而简单的:

这现在是标准库的一部分:unsafeAddressOf。

所以你问题的答案是

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

以下是被标记为正确的原始答案(为了后代/礼貌):

Swift“隐藏”指针,但它们仍然存在于底层。(因为运行时需要它,并且出于与Objc和C的兼容性原因)

然而,有几件事要知道,但首先如何打印一个Swift字符串的内存地址?

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

这将打印字符串的内存地址,如果你打开XCode -> Debug Workflow -> View memory并进入打印的地址,你将看到字符串的原始数据。 因为这是一个字符串字面值,所以这是二进制存储中的内存地址(不是堆栈或堆)。

然而,如果你这样做

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

    // example printed address 0x103f30020

这将在堆栈上,因为字符串是在运行时创建的

注意:.core。_baseAddress没有文档,我发现它在变量检查器中查找,它可能在未来被隐藏

_baseAddress不是在所有类型上都可用,这里是另一个使用CInt的例子

    var testNumber : CInt = 289
    takesInt(&testNumber)

哪里takesInt是这样的C辅助函数

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

在Swift方面,这个函数是takesInt(intptr: CMutablePointer<CInt>),所以它需要一个CMutablePointer到一个CInt,你可以用&varname获取它

函数输出0x7fff5fbfed98,在这个内存地址中,您将找到289(以十六进制表示)。您可以使用*intptr = 123456更改其内容

现在,还有一些需要知道的事情。

在swift中,String是基本类型,而不是对象。 CInt是一个Swift类型映射到C int类型。 如果你想要一个对象的内存地址,你必须做一些不同的事情。 Swift有一些指针类型,可以在与C交互时使用,你可以在这里阅读:Swift指针类型 此外,你可以了解更多关于它们的声明(cmd+单击类型),以了解如何将一种类型的指针转换为另一种类型的指针

    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是我用这个实现创建的C helper函数

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

同样,一个地址打印的例子:0x6000000530b0,如果你通过内存检查器,你会找到你的NSString

你可以用Swift中的指针做一件事(这甚至可以用inout参数完成)

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

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

或者,与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

其他回答

请注意,这个答案是相当古老的。书中描述的许多方法已经不再有效。特别是不能再访问.core。

但是@drew的回答是正确而简单的:

这现在是标准库的一部分:unsafeAddressOf。

所以你问题的答案是

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

以下是被标记为正确的原始答案(为了后代/礼貌):

Swift“隐藏”指针,但它们仍然存在于底层。(因为运行时需要它,并且出于与Objc和C的兼容性原因)

然而,有几件事要知道,但首先如何打印一个Swift字符串的内存地址?

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

这将打印字符串的内存地址,如果你打开XCode -> Debug Workflow -> View memory并进入打印的地址,你将看到字符串的原始数据。 因为这是一个字符串字面值,所以这是二进制存储中的内存地址(不是堆栈或堆)。

然而,如果你这样做

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

    // example printed address 0x103f30020

这将在堆栈上,因为字符串是在运行时创建的

注意:.core。_baseAddress没有文档,我发现它在变量检查器中查找,它可能在未来被隐藏

_baseAddress不是在所有类型上都可用,这里是另一个使用CInt的例子

    var testNumber : CInt = 289
    takesInt(&testNumber)

哪里takesInt是这样的C辅助函数

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

在Swift方面,这个函数是takesInt(intptr: CMutablePointer<CInt>),所以它需要一个CMutablePointer到一个CInt,你可以用&varname获取它

函数输出0x7fff5fbfed98,在这个内存地址中,您将找到289(以十六进制表示)。您可以使用*intptr = 123456更改其内容

现在,还有一些需要知道的事情。

在swift中,String是基本类型,而不是对象。 CInt是一个Swift类型映射到C int类型。 如果你想要一个对象的内存地址,你必须做一些不同的事情。 Swift有一些指针类型,可以在与C交互时使用,你可以在这里阅读:Swift指针类型 此外,你可以了解更多关于它们的声明(cmd+单击类型),以了解如何将一种类型的指针转换为另一种类型的指针

    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是我用这个实现创建的C helper函数

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

同样,一个地址打印的例子:0x6000000530b0,如果你通过内存检查器,你会找到你的NSString

你可以用Swift中的指针做一件事(这甚至可以用inout参数完成)

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

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

或者,与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

引用类型:

获取引用类型的内存地址是有意义的,因为它表示标识。 ===标识运算符用于检查两个对象是否指向同一个引用。 使用ObjectIdentifier获取内存地址

代码:

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

值类型:

获取值类型的内存地址的需求并不太重要(因为它是一个值),重点将更多地放在值的相等性上。

如果你只是想在调试器中看到这个,而不做任何其他事情,实际上没有必要获得Int指针。要在内存中获取对象地址的字符串表示形式,只需使用如下方法:

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

使用示例:

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

此外,请记住,你可以简单地打印一个对象,而不重写它的描述,它将显示它的指针地址与更多的描述性(如果经常是隐晦的)文本。

print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...

获取一个对象的(堆)地址

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

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

(编辑:Swift 1.2现在包含了一个类似的叫做unsafeAddressOf的函数。)

在Objective-C中,这将是[NSString stringWithFormat:@"%p", o]。

O是对实例的引用。因此,如果o被赋值给另一个变量o2, o2的返回地址将是相同的。

这并不适用于结构体(包括String)和基本类型(如Int),因为它们直接存在于堆栈上。但我们可以检索堆栈上的位置。

获取结构、内置类型或对象引用的(堆栈)地址

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中,这将是[NSString stringWithFormat:@"%p", &o]或[NSString stringWithFormat:@"%p", &i]。

S是结构。因此,如果s被赋值给另一个变量s2,值将被复制,s2的返回地址将不同。

它是如何组合在一起的(指针概述)

像在Objective-C中一样,有两个不同的地址与o相关。第一个是对象的位置,第二个是对象的引用(或指针)的位置。

是的,这意味着地址0x7fff5fbfe658的内容是数字0x6100000011d0,调试器可以告诉我们:

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

除了字符串是结构体,在内部这和(Objective-)C的工作原理是一样的。

(目前为Xcode 6.3)

我对Swift 3的解决方案

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

这段代码创建的描述类似于默认描述 < MyClass: 0 x610000223340 >