Skip to content

Instantly share code, notes, and snippets.

@aufflick
Last active November 6, 2021 06:55
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save aufflick/83b74f3a3bc201b0b3e6 to your computer and use it in GitHub Desktop.
Helpers to assist using the ObjC runtime to associate both objects and structs in Swift
// Associated wrapper by WeZZard : https://wezzard.com/2015/10/09/associated-object-and-swift-struct/
// Type safe helpers inspired by Tikitu de Jager : https://medium.com/@ttikitu/swift-extensions-can-add-stored-properties-92db66bce6cd#.mx6ekrw16
public final class AssociatedStruct<T>: NSObject, NSCopying {
public typealias Type = T
public let value: Type
public init(_ value: Type) { self.value = value }
public func copyWithZone(zone: NSZone) -> AnyObject {
return self.dynamicType.init(value)
}
}
extension AssociatedStruct where T: NSCopying {
public func copyWithZone(zone: NSZone) -> AnyObject {
return self.dynamicType.init(value.copyWithZone(zone) as! Type)
}
}
extension NSObject {
func associatedOptionalObject<ValueType: AnyObject>(
key: UnsafePointer<String>,
initialiser: () -> ValueType?) -> ValueType? {
if let obj = objc_getAssociatedObject(self, key) as? ValueType {
return obj
}
let obj = initialiser()
self.associateOptionalObject(key, value:obj)
return obj
}
func associateOptionalObject<ValueType: AnyObject>(key: UnsafePointer<String>, value: ValueType?) {
objc_setAssociatedObject(self, key, value, .OBJC_ASSOCIATION_RETAIN)
}
func associatedObject<ValueType: AnyObject>(
key: UnsafePointer<String>,
initialiser: () -> ValueType) -> ValueType {
if let obj = objc_getAssociatedObject(self, key) as? ValueType {
return obj
}
let obj = initialiser()
self.associateOptionalObject(key, value:obj)
return obj
}
func associateObject<ValueType: AnyObject>(key: UnsafePointer<String>, value: ValueType) {
objc_setAssociatedObject(self, key, value, .OBJC_ASSOCIATION_RETAIN)
}
func associatedOptionalStruct<ValueType: Any>(
key: UnsafePointer<String>,
initialiser: () -> ValueType?) -> ValueType? {
if let obj = objc_getAssociatedObject(self, key) as? AssociatedStruct<ValueType?> {
return obj.value
}
let value = initialiser()
self.associateOptionalStruct(key, value:value)
return value
}
func associateOptionalStruct<ValueType: Any>(key: UnsafePointer<String>, value: ValueType?) {
objc_setAssociatedObject(self, key, AssociatedStruct<ValueType?>(value), .OBJC_ASSOCIATION_RETAIN)
}
func associatedStruct<ValueType: Any>(
key: UnsafePointer<String>,
initialiser: () -> ValueType) -> ValueType {
if let obj = objc_getAssociatedObject(self, key) as? AssociatedStruct<ValueType> {
return obj.value
}
let value = initialiser()
self.associateOptionalStruct(key, value:value)
return value
}
func associateStruct<ValueType: Any>(key: UnsafePointer<String>, value: ValueType) {
objc_setAssociatedObject(self, key, AssociatedStruct<ValueType>(value), .OBJC_ASSOCIATION_RETAIN)
}
}
let foo = NSNumber(int:5)
private var anOptionalColourKey = "anOptionalColourKey"
private var aColourKey = "aColourKey"
private var anOptionalStringKey = "anOptionalStringKey"
private var aStringKey = "aStringKey"
extension NSNumber {
var anOptionalColour : UIColor? {
get {
return self.associatedOptionalObject(&anOptionalColourKey) { return nil as UIColor? }
}
set {
self.associateOptionalObject(&anOptionalColourKey, value: newValue)
}
}
var aColour : UIColor {
get {
return self.associatedObject(&aColourKey) {
return UIColor.blackColor()
}
}
set {
self.associateObject(&aColourKey, value: newValue)
}
}
var anOptionalString : String? {
get {
return self.associatedOptionalStruct(&anOptionalStringKey) {
return nil as String?
}
}
set {
self.associateOptionalStruct(&anOptionalStringKey, value: newValue)
}
}
var aString : String {
get {
return self.associatedStruct(&aStringKey) {
return ""
}
}
set {
self.associateStruct(&aStringKey, value: newValue)
}
}
}
foo.anOptionalColour
foo.anOptionalColour = UIColor.greenColor()
foo.anOptionalColour
foo.anOptionalColour = nil
foo.anOptionalColour
foo.aColour
foo.aColour = UIColor.redColor()
foo.aColour
foo.anOptionalString
foo.anOptionalString = "42"
foo.anOptionalString
foo.anOptionalString = nil
foo.anOptionalString
foo.aString
foo.aString = "Hello World"
foo.aString
foo.aString = "Goodbye World"
foo.aString
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment