12

There is something I am not understanding about how Swift manages memory address of String(s)

1. Reference types

Here foo and boo are 2 pointers to the same memory location.

class Foo { }

let foo = Foo()
let boo = foo

unsafeAddressOf(foo) // "UnsafePointer(0x7FCD13719BE0)"
unsafeAddressOf(boo) // "UnsafePointer(0x7FCD13719BE0)" 

Good.

2. Value types

let word0 = "hello"
let word1 = word0

Now word0 and word1 are value types but here the copy on write mechanism is involved.

[...] However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_134

So why do they have 2 different memory addresses?

unsafeAddressOf(word0) // "UnsafePointer(0x7FCD1342ACE0)"
unsafeAddressOf(word1) // "UnsafePointer(0x7FCD13414260)"

3. More

Also please note that String is a struct that somehow conforms to AnyObject.

Tested with Xcode 7 GM Playground and Swift 2.0.

Community
  • 1
  • 1
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    "So why do they have 2 different memory addresses?" So why do you care? – matt Sep 17 '15 at 19:57
  • 5
    String is automatically bridged to NSObject when passed to a function expecting AnyObject, see also my comment to http://stackoverflow.com/questions/32637688/is-it-possible-to-mutate-a-string-in-swift-such-that-it-can-be-proven-to-modify. Actually I get the same output for word0/1 in a compiled project, but different output in a Playground. – Martin R Sep 17 '15 at 20:02
  • @matt Ahah...:D Yes. I'm starting to think the same thing. But this question http://stackoverflow.com/questions/32626383/do-instance-references-really-work-in-swift and the intense exchange of comments below my answer pushed me to ask this question. – Luca Angeletti Sep 17 '15 at 20:02
  • 1
    Similar observations here: http://stackoverflow.com/questions/31298461/a-different-bridging-between-array-and-dictionary. I think that you cannot make any assumption on whether the automatic bridging to a Foundation object returns the same instance each time or not. – Martin R Sep 17 '15 at 20:06
  • @MartinR: understood. Thank you a lot. If you want to write your comments as an answer consider it accepted. – Luca Angeletti Sep 17 '15 at 20:07

2 Answers2

13
func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>

takes an AnyObject parameter, i.e. an instance of a class. It returns the pointer to the storage used for the object referenced by object.

addressOf() cannot be used with struct variables:

struct Foo { }
var f = Foo()
let a = unsafeAddressOf(f)
// error: cannot invoke 'unsafeAddressOf' with an argument list of type '(Foo)'

String is a struct, however, it is automatically bridged to NSString when passed to a function expecting an object. So

let word0 = "hello"
let p1 = unsafeAddressOf(word0)

actually executes

let p1 = unsafeAddressOf(word0 as NSString)

You get not the address of the word0 variable, but the pointer to the memory location of the bridged NSString object.

It seems that you cannot make any assumptions on whether this bridging returns the identical NSString object (or more generally, the same Foundation object) when done repeatedly on the same Swift string. In a Playground, even

let word0 = "hello"
let p1 = unsafeAddressOf(word0)
let p2 = unsafeAddressOf(word0)
let p3 = unsafeAddressOf(word0)

returns three different addresses (but the same addresses in a compiled project). The same observation (for arrays and dictionaries) was made in A different bridging between Array and Dictionary.

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • So then how can we apply this to structs? If I want the memory address of a custom struct, the TRUE mem address, zero casting as a foundation class object, what can I do? – karan satia Jul 21 '16 at 17:25
-1

Swift 3.0 Unmanaged.passUnretained(object).toOpaque()

invoodoo
  • 3,905
  • 1
  • 18
  • 16