objc_getAssociatedObject and Runtime attributes

I have the following extension which was used to automatically save/retrieve runtime attributes unique to a UIImageView:

import UIKit

var imgAttributeKey:String? = nil

extension UIImageView {
    
    var imgAttribute: String? {
        get { return objc_getAssociatedObject(self, &imgAttributeKey) as? String }
        set { objc_setAssociatedObject(self, &imgAttributeKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
    
}

This was working fine but after trying the code again recently, the getters were always returning nil. Did something change in Swift 5 version that could be breaking this implementation? Any suggestions on how to go about it?

Answered by OOPer in 679368022

it's not being called during the XIB decoding process, 

Sorry, I had not noticed the image was an example of storyboard settings. (You should better have mentioned it explicitly.)

But I cannot reproduce the getters were always returning nil. I got this:

Failed to set (imgAttribute) user defined inspected property on (UIImageView): [<UIImageView 0x7ff072e080f0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key imgAttribute.

Not always returning nil.

The User Defined Runtime Attributes uses Key Value Coding, which is one of the dynamic feature of Objective-C. Since Swift 4 (not Swift 5), you need to add an explicit annotation @objc for such methods and properties.

extension UIImageView {
    
    @objc var imgAttribute: String? {
        get { return objc_getAssociatedObject(self, &imgAttributeKey) as? String }
        set { objc_setAssociatedObject(self, &imgAttributeKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
    
}

With this change, I can get the value shown in the User Defined Runtime Attributes:

Optional("someAttr")

What do you get with this change?

the getters were always returning nil.

I cannot reproduce the same issue, iOS 14.5 simulator/Xcode 12.5. A simple code like print(imageView.imgAttribute) has output:

Optional("Test")

Can you clarify how have you tested it?

Accepted Answer

it's not being called during the XIB decoding process, 

Sorry, I had not noticed the image was an example of storyboard settings. (You should better have mentioned it explicitly.)

But I cannot reproduce the getters were always returning nil. I got this:

Failed to set (imgAttribute) user defined inspected property on (UIImageView): [<UIImageView 0x7ff072e080f0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key imgAttribute.

Not always returning nil.

The User Defined Runtime Attributes uses Key Value Coding, which is one of the dynamic feature of Objective-C. Since Swift 4 (not Swift 5), you need to add an explicit annotation @objc for such methods and properties.

extension UIImageView {
    
    @objc var imgAttribute: String? {
        get { return objc_getAssociatedObject(self, &imgAttributeKey) as? String }
        set { objc_setAssociatedObject(self, &imgAttributeKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) }
    }
    
}

With this change, I can get the value shown in the User Defined Runtime Attributes:

Optional("someAttr")

What do you get with this change?

objc_getAssociatedObject and Runtime attributes
 
 
Q