Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Associated objects in Swift, does global key actually produce specific instances?

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?

like image 680
Fattie Avatar asked Jan 24 '17 12:01

Fattie


1 Answers

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.

like image 161
Nikolai Ruhe Avatar answered Sep 20 '22 14:09

Nikolai Ruhe