4

I was learning Python and wanted to confirm a certain behavior in Objective-C and Swift.

The test was as follows:

Python

def replace(list):
    list[0] = 3
    print(list)

aList = [1, 2, 3]
print(aList)
replace(aList)
print(aList)

Objective-C

- (void)replace:(NSMutableArray *)array {
    array[0] = @1;
    NSLog(@"array: %@, address: %p\n%lx", array, array, (long)&array);
}

NSMutableArray *array = [@[@1, @2, @3] mutableCopy];
NSLog(@"original: %@, address: %p \n%lx", array, array, (long)&array);
[self replace:array];
NSLog(@"modified: %@, address: %p \n%lx", array, array, (long)&array);

Swift

var numbers = [1, 2, 3]
let replace = { (var array:[Int]) -> Void in
    array[0] = 2
    print("array: \(array) address:\(unsafeAddressOf(array as! AnyObject))")
}

print("original: \(numbers) address:\(unsafeAddressOf(numbers as! AnyObject))")
replace(numbers)
print("modified: \(numbers) address:\(unsafeAddressOf(numbers as! AnyObject))")

All the results came out as expected except for the address part in Swift. In Objective-C, the address of array remained the same in original and modified, but the print result of Swift was:

original: [1, 2, 3] address:0x00007f8ce1e092c0
array: [2, 2, 3] address:0x00007f8ce1f0c5d0
modified: [1, 2, 3] address:0x00007f8ce4800a10

Is there something I'm missing?

2
  • unsafeAddressOf(numbers) doesn't work. Here's the error: error: argument type '[Int]' does not conform to expected type 'AnyObject' Commented Dec 14, 2015 at 9:17
  • That might be an Xcode version thing (in Xcode 7.2 it works). Anyway, my observation was that if you're interested in some of the details of what's going on behind the scenes when you mutate a value type (and Array is a struct, a value type), see the latter part of WWDC 2015 video Building Better Apps with Value Types in Swift. Note, if you want reference type behavior in Swift, use NSMutableArray (a class), rather than the Array (a struct). Commented Dec 14, 2015 at 9:45

1 Answer 1

9

Arrays in Swift have value semantics, not the reference semantics of arrays in Python and Objective-C. The reason you're seeing different addresses (and addresses at all) is that every time you do an as! AnyObject cast, you're actually telling Swift to bridge your Array<Int> struct to an instance of NSArray. Since you bridge three times, you get three different addresses.


You shouldn't need to think about the address of a Swift array, but if you'd like to (momentarily) get the address of an array's buffer, you can do it this way:

func getBufferAddress<T>(array: [T]) -> String {
    return array.withUnsafeBufferPointer { buffer in
        return String(reflecting: buffer.baseAddress)
    }
}

This lets you see the buffer's copy-on-write in action:

var numbers = [1, 2, 3]
let numbersCopy = numbers

// the two arrays share a buffer here
print(getBufferAddress(numbers))                 // "0x00007fba6ad16770"
print(getBufferAddress(numbersCopy))             // "0x00007fba6ad16770"

// mutating `numbers` causes a copy of its contents to a new buffer
numbers[0] = 4

// now `numbers` has a new buffer address, while `numbersCopy` is unaffected
print(getBufferAddress(numbers))                 // "0x00007ff23a52cc30"
print(getBufferAddress(numbersCopy))             // "0x00007fba6ad16770"
Sign up to request clarification or add additional context in comments.

4 Comments

Is there any way to get the address like in Objective-C? Or is that quite irrelevant in Swift?
Irrelevant in Swift! Added a note in the answer.
I set a breakpoint and in lldb called frame var -L numbers and frame var -L numbersCopy and the memory addresses were different. Any idea why it doesn't match up with the printed buffer address here?
Array is defined as a struct that stores a pointer to its storage, so with that lldb command I think you're seeing the stack addresses of the two different variables, not the heap address of their shared underlying storage.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.