Search code examples
iosswiftpass-by-pointerinout

Inout parameters don't have the same address


I have three classes A, B and C. A has a resource called rA. What I am trying to achieve is that all of those instances have a reference to the exact same resource.

So to concrete in Swift terms:

Class A has a property called foo:

private var foo : [Bar] = [Bar]() // shared resource

Class B has a property called foo which is passed into the initializer as an inout parameter:

private var foo : [Bar]!
init(inout foo:[Bar]){
    self.foo = foo
}

Class C is analogous to Class B

How come, if I pass foo from Class A to Class B (or C) the address changes ?

In A I would pass it to B (or C) like so:

let b = B(foo: &self.foo)

When I print the address after initialization of foo in A it gives me a different address than after assignment in B.

class A{
    private var foo = [Bar]()
    func someFunc(){
        NSLog("\n\n [A] \(unsafeAddressOf(self.foo))\n\n") // different from output in B
        let b = B(foo: &self.foo)

    }
}

class B{
    private var foo: [Bar]!
    init(inout foo: [Bar]){
         self.foo = foo
         NSLog("\n\n [B] \(unsafeAddressOf(self.foo))\n\n")
    }
}

Any ideas why this is the case ?


Solution

  • Swift arrays are value types, therefore in

    self.foo = foo
    

    you assign the value of foo to self.foo. This are two independent arrays now (even if the actual elements are copied only when one of the arrays is mutated).

    Also you cannot take the address of a Swift array with unsafeAddressOf() because that function takes an AnyObject parameter which is an instance of a class, i.e. a value type. In

     unsafeAddressOf(self.foo)
    

    the Swift compiler actually bridges the Swift array to an NSArray. As demonstrated in Swift, Strings and Memory Addresses, this may or may not result in the same object when done repeatedly. In any case, the printed address is not the storage location of the Swift array.

    If you need a real reference which you can pass around then you can wrap the array in a class. Using NS(Mutable)Array might also be an option, but then you lose many Swift features.