8

To have an associated object in Swift, you simply use a memory address as a handle, and then use the objc calls.

The usual example code you can google everywhere is:

var keyA:UInt8 = 0
var keyB:UInt8 = 0
extension UIViewController {

    var aoAA: String? {
        get { return objc_getAssociatedObject(self, &keyA) as? String }
        set { objc_setAssociatedObject(self, &keyA, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
    var aoBB: String? {
        get { return objc_getAssociatedObject(self, &keyB) as? String }
        set { objc_setAssociatedObject(self, &keyB, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
}

this works fine,

class Thing: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        aoAA = "this is a"
        print("...... \(aoAA)")
        aoBB = "this is b"
        print("...... \(aoBB)")
        aoAA = "changed A"
        print("...... \(aoAA) \(aoBB)")
        aoBB = "changed B"
        print("...... \(aoAA) \(aoBB)")
        aoAA = aoBB
        print("...... \(aoAA) \(aoBB)")
        }

But wait...

The handles, keyA and keyB, are global to the whole project.

When you use aoAA and aoBB in different UIViewController, how can it possibly be that aoAA and aoBB act as properties specific to that instance?

Surely there is only "one" aoAA everywhere in the project?

ie, aoAA is a global - just as the handle keyA is a global?

My testing seemed to show that they are independent variables, specific to different instances of different UIViewControllers, but that seems barmy.

How can each instance of aoAA possibly be different - it's using the same global handle?

Hamish
  • 78,605
  • 19
  • 187
  • 280
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • 2
    u pass a reference for a "self" in each call, so it sets the associated object to your UIViewController instance – Orest Savchak Jan 24 '17 at 12:55
  • hi @orest ... thanks ... but then it uses &keyA in the call. there is only one "&keyA" in the entire build of the app. ? – Fattie Jan 24 '17 at 13:41
  • 1
    Yep, it uses an address of keyA, address should be unique for the keyA during all the application is running – Orest Savchak Jan 24 '17 at 13:58
  • Ah, so say the key value is "1234". Do you mean, it uses BOTH the object value as a key ("self" for us) AND the key as a key ("1234") each time it is called? So the "key" it uses is some combination of BOTH the key ("1234") and the object (the various "self" in our example). Is that right? – Fattie Jan 24 '17 at 14:02
  • 1
    Hey @JoeBlow, I always seem to be changing your [swift3] tags to [swift] tags – note that the [swift3] tag is only for questions directly related to *changes* in the language as a result of Swift 3, whereas [swift] is for general language questions (as per their respective tag wikis). This question will be just as relevant when Swift 4 comes around :) – Hamish Jan 24 '17 at 14:32

1 Answers1

9

Objective-C's concept of "associated objects" lets you connect one "target" object instance with one "source" object instance. It's a unidirectional association where only the source knows the target:

Associated Objects with source and target instances

objc_setAssociatedObject(source, key, target, ...)

The association uses a key to be able to connect and distinguish any number of associated objects with one source. The keys must obviously be different—but just for one source instance.

Because you have to provide both the key and the source instance to retrieve the associated object, it's not necessary to use really unique keys. The implementation of objc_***AssociatedObject can form a process-unique key by combining the instance pointer and the key.

So for your example, yes, both aoAA and aoBB will return individual values per each UIViewController instance, even though keyA and keyB are global.

To be absolutely clear, you do need different keys for each associated object in a given extension. So, aoAA and aoBB each need their own key, as shown in the example code (to wit, the pointers to keyA and keyB). But as is asked in the question it's correct have only one key for each associated object, no matter how many conforming classes the extension is used in.

Fattie
  • 27,874
  • 70
  • 431
  • 719
Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200