2

According to Apple's Swift guide:

If you create an array, a set, or a dictionary, and assign it to a variable, the collection that is created will be mutable. This means that you can change (or mutate) the collection after it is created by adding, removing, or changing items in the collection. If you assign an array, a set, or a dictionary to a constant, that collection is immutable, and its size and contents cannot be changed.

But in Xcode 7.2.1, I get these results:

import Foundation  //**Added per comments**

var data: [Int] = [10, 20]
print(unsafeAddressOf(data))

data.append(30)

print(data)
print(unsafeAddressOf(data))

--output:--
0x00007ff9a3e176a0
[10, 20, 30]
0x00007ff9a3e1d310

Because I assigned the array to a var, I expected to see the same address for data after appending a value to data.

Another example:

class Item {
}

var data: [Item] = [Item(), Item()]
print(unsafeAddressOf(data))

data.append(Item())

print(data)
print(unsafeAddressOf(data))

--output:--
0x00007f86a941b090
[Item, Item, Item]
0x00007f86a961f4c0

And another:

var data: [String] = ["a", "b"]
print(unsafeAddressOf(data))

data[0] = "A"

print(data)
print(unsafeAddressOf(data))

--output:--
0x00007faa6b624690
["A", "b"]
0x00007faa6b704840
3
  • In Xcode 7.3 it does not compile. [Int] does not confirm to AnyObject. Commented Apr 19, 2016 at 5:55
  • @Thilo, Don't declare the type then--let Swift infer the type. The type of the array is irrelevant. Commented Apr 19, 2016 at 5:57
  • Why do you expect the same address ??? I don't ... Commented Apr 19, 2016 at 6:27

2 Answers 2

2

First of all, your example only compiles if it has import Foundation at the top. Because without it Array is just structure that does not conform to AnyObject protocol that used in unsafeAddressOf(object: AnyObject) signature. Read more here:

Instances of the Swift String structure type cannot be represented by the AnyObject type, because AnyObject only represents instances of a class type. However, when bridging to Foundation is enabled, Swift String values can be assigned to constants and variables of AnyObject type as bridged instances of the NSString class.

That's also true for arrays (Array is bridged to NSArray), sets (Set is bridged to NSSet), dictionaries (Dictionary is bridged to NSDictionary) and numbers (Int, UInt, Float, Double, Bool is bridged to NSNumber).

So every time you call unsafeAddressOf(data) data structure is implicitly bridged to unique NSArray object and because of that you see different address each time. Also if you do not mutate structure between calls to unsafeAddressOf() bridged NSArray object can be the same. I think that's because of optimization.

Try this code in Playground:

import Foundation

func printData(data: AnyObject) {
    //print(data) // uncomment to see data value
    print(unsafeAddressOf(data))
}

var data = [10, 20]

printData(data)

data.append(30)

printData(data)

var nsArray = data as NSArray

printData(nsArray)

Run it several times and you'll see that sometimes two last printed addresses are the same and sometimes it's not.

In general your question does not relate to mutability of value types. All you see happens only because Swift value types are bridged to Foundation reference types.

Sign up to request clarification or add additional context in comments.

1 Comment

First of all, your example only compiles if it has import Foundation at the top. -- Ah. Is that what Thilo was going on about? I'm sorry, it was sloppy of me: I do have an import Foundation statement at the top of my playground. I'll edit my question to reflect that.
0

I don't know about the memory address (I could not get your code to compile on Xcode 7.3, and either way it seems the compiler is free to optimize the exact memory management), but arrays have value-type semantics, so if you modify an array through one variable it will not have an effect on any other variable that you initialized with the same array.

var data: [Int] = [10, 20]
var copy = data    // makes a copy (at least conceptually), not a shared reference

data.append(30)

print(data)   // 10, 20, 30
print(copy)   // still only 10, 20

Does not answer your question maybe, but explains why it is not necessary to keep the address constant.

3 Comments

Yeah, I know arrays are value types. If my results are how things should be, then the docs should merely state: You can reassign to a var, but not a let. Claiming that the collection itself is mutable is not borne out by my results--even when I use an index to change a value.
Well, you have something else in data than you had before. That's mutable, no? And you could do that without reassigning to the variable. All done through a call to a mutating function. Not clear what else "mutable" should mean for a value-type.
@7stud "You can reassign to a var, but not a let." You can, why not? var a = [1,2,3]; let b = a; a += [4]; is legal. a is var representing the mutable array and b is let representing the constant array. var c = b; c is mutable array. all three (a,b,c) are totally independent, because an array is value type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.