I’m curious if anyone has found a way to use associated objects within Swift’s strict concurrency model. The objective c based function calls (objc_setAssociatedObject
and objc_getAssociatedObject
) have a const void *key
argument. Typically, this is obtained by having a private global variable which is passed as an inout argument.
E.g.
private var myKey: Void?
extension MyProtocol {
var myAddedString: String? {
get {
objc_getAssociatedObject(self, &myKey) as? String
}
set {
objc_setAssociatedObject(self, &myKey, newValue, .OBJC_ASSOCIATION_COPY)
}
}
}
This approach does not appear to be compatible with Swift strict concurrency, though, because myKey
is “non-isolated global shared mutable state”. I can’t change the var
to be a let
, which would solve the concurrency issue, as then it can’t be used as an inout argument.
I’m curious if anyone has found a way around this other than binding myKey
to a global actor.
1
You don’t need a var
and &
to get a UnsafeRawPointer
– you can just create one with init(bitPattern:)
:
let myKey = UnsafeRawPointer(bitPattern: 1)!
This does not guarantee that the key is unique, however.
To get a unique value, we can declare a type, and get the ObjectIdentifier
of that type.
enum MyKey {}
let myKey = UnsafeRawPointer(bitPattern: Int(bitPattern: ObjectIdentifier(MyKey.self)))!
get {
// do not write '&' here!
objc_getAssociatedObject(self, myKey) as? String
}
2
You can make the key nonisolated(unsafe)
given that you’re not mutating it (and neither do objc_getAssociatedObject
nor objc_setAssociatedObject)
). It’s just using the address. So:
private nonisolated(unsafe) var myKey: Void?