This can actually be easily reproducible on a Playground:
import UIKit
private let _delegateKey = malloc(4)
@objc protocol SwiftyGifDelegate: AnyObject { }
class SomeObject: SwiftyGifDelegate { }
extension UIImageView {
var delegate: SwiftyGifDelegate? {
get { return objc_getAssociatedObject(self, _delegateKey!) as? SwiftyGifDelegate }
set { objc_setAssociatedObject(self, _delegateKey!, newValue, .OBJC_ASSOCIATION_ASSIGN) }
}
}
let imageView = UIImageView()
autoreleasepool {
let object = SomeObject()
imageView.delegate = object
}
debugPrint(imageView.delegate)
Solution
Introduce a objc_setAssociatedWeakObject and objc_getAssociatedWeakObject to avoid the crash. Instead of using the OBJC_ASSOCIATION_ASSIGN with the pointer directly, We can use a block that stores a weak reference, and then use OBJC_ASSOCIATION_COPY for the block.
On the playground, if you replace the previous methods with the new ones, you will see that it doesn't crash anymore accessing the nil delegate.
Description
It looks that the previous fix: https://github.com/kirualex/SwiftyGif/pull/158 didn't actually fixed the root of the problem. After more investigation, it seems the issue is related to
objc_associatedObject
API. TheOBJC_ASSOCIATION_ASSIGN
does not weakify references. More details about the issue can be found here: https://stackoverflow.com/questions/16569840/using-objc-setassociatedobject-with-weak-referencesHow to reproduce
This can actually be easily reproducible on a Playground:
Solution
Introduce a
objc_setAssociatedWeakObject
andobjc_getAssociatedWeakObject
to avoid the crash. Instead of using theOBJC_ASSOCIATION_ASSIGN
with the pointer directly, We can use a block that stores a weak reference, and then useOBJC_ASSOCIATION_COPY
for the block.On the playground, if you replace the previous methods with the new ones, you will see that it doesn't crash anymore accessing the
nil
delegate.