2

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 ?

the_critic
  • 12,720
  • 19
  • 67
  • 115
  • `unsafeAddressOf()` takes an `AnyObject` parameter, therefore in your case the Swift array with type `[Bar]` is bridged to an `NSArray`. This bridging may or may not result in the same object when done repeatedly. – Martin R Dec 10 '15 at 21:23
  • @MartinR Thanks, that makes sense. Is there any other way I can check if they reference the same object ? – the_critic Dec 10 '15 at 21:25
  • Note that Swift arrays are *value types* and `self.foo = foo` "copies" the array (even if the actual elements are only copied on demand). – If you need a real *reference* which you can pass around then you can wrap the array in a `class`. Or use `NS(Mutable)Array` but then you lose many Swift features. – Martin R Dec 10 '15 at 21:29
  • That's why I love you @MartinR. Always tremendously helpful. Pack your comments into an answer and I'll reward you! – the_critic Dec 10 '15 at 21:32

1 Answers1

3

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.

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382