Swift 如何extension(拓展)存储属性

2022-03-30  本文已影响0人  诗颜语

语法层面是不支持的,与OC一样通常使用关联对象实现
本文书写时Swift5.6

第一种

第一种就是static var修饰的变量加&,或者全局的 var 变量加&
通过这种方式添加的属性被拓展的类 不需要通过@objc修饰,不需要非得继承NSObject

class Test {
    
}
// or
// var testKey: String?
// var test1Key: String?
extension Test {
    private static var testKey = true
    
    var test: String {
        get {
            return objc_getAssociatedObject(self, &Self.testKey) as! String
        }
        set {
            objc_setAssociatedObject(self, &Self.testKey, newValue, .OBJC_ASSOCIATION_COPY)
        }
    }
    
    private static var test1Key = true
    
    var test1: String {
        get {
            return objc_getAssociatedObject(self, &Self.test1Key) as! String
        }
        set {
            objc_setAssociatedObject(self, &Self.test1Key, newValue, .OBJC_ASSOCIATION_COPY)
        }
    }
}
do {
    let obj = Test()
    obj.test = "123"
    obj.test1 = "789"
    print(obj.test)
    print(obj.test1)
}

do {
    let obj = Test()
    obj.test = "456"
    obj.test1 = "000"
    print(obj.test)
    print(obj.test1)
}

do {
    let obj = Test()
    obj.test = "999"
    obj.test1 = "555"
    print(obj.test)
    print(obj.test1)
}


第二种

通过selector当前属性的setter or getter 方法,相当于OC时的_cmd & @selector()
通过这种方式添加的属性 需要通过@objc修饰,因为#selector()只能包裹被@objc修饰的方法,不需要非得继承NSObject

extension NSObject {
    func setAssociated(key: Selector, value: Any?, policy: objc_AssociationPolicy) {
       let p = unsafeBitCast(key, to: UnsafeRawPointer.self)
       objc_setAssociatedObject(self, p, value, policy)
   }
   
   func getAssociated<T>(key: Selector) -> T? {
       let p = unsafeBitCast(key, to: UnsafeRawPointer.self)
       return objc_getAssociatedObject(self, p) as? T
   }
}

@objc extension NSObject {

    var test: String {
        get {
            getAssociated(key: #selector(setter: self.test)) ?? ""
        }
        set {
            setAssociated(key: #selector(setter: test), value: newValue, policy: .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }

    var test1: String {
        get {
            getAssociated(key: #selector(setter: self.test1)) ?? ""
        }
        set {
            setAssociated(key: #selector(setter: test1), value: newValue, policy: .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
}


do {
    let obj = NSObject()
    obj.test = "123"
    obj.test1 = "789"
    print(obj.test)
    print(obj.test1)
}

do {
    let obj = NSObject()
    obj.test = "456"
    obj.test1 = "000"
    print(obj.test)
    print(obj.test1)
}

do {
    let obj = NSObject()
    obj.test = "999"
    obj.test1 = "555"
    print(obj.test)
    print(obj.test1)
}

do {
    let p = unsafeBitCast(#selector(setter: NSObject.test), to: UnsafeRawPointer.self)
    print(#function, p)
}
do {
    let p = unsafeBitCast(#selector(setter: NSObject.test), to: UnsafeRawPointer.self)
    print(#function, p)
}
do {
    let p = unsafeBitCast(#selector(setter: NSObject.test), to: UnsafeRawPointer.self)
    print(#function, p)
}
do {
    let p = unsafeBitCast(#selector(getter: NSObject.test), to: UnsafeRawPointer.self)
    print(#function, p)
}
do {
    let p = unsafeBitCast(#selector(setter: NSObject.test1), to: UnsafeRawPointer.self)
    print(#function, p)
}
do {
    let p = unsafeBitCast(#selector(getter: NSObject.test1), to: UnsafeRawPointer.self)
    print(#function, p)
}

第二种改进写法 - 利用协议

protocol AssociatedObject {}

extension AssociatedObject {
    func setAssociated(key: Selector, value: Any?, policy: objc_AssociationPolicy) {
       let p = unsafeBitCast(key, to: UnsafeRawPointer.self)
       objc_setAssociatedObject(self, p, value, policy)
   }
   
   func getAssociated<T>(key: Selector) -> T? {
       let p = unsafeBitCast(key, to: UnsafeRawPointer.self)
       return objc_getAssociatedObject(self, p) as? T
   }
}

class Test {}

@objc extension Test: AssociatedObject {

    var test: String {
        get {
            getAssociated(key: #selector(setter: self.test)) ?? ""
        }
        set {
            setAssociated(key: #selector(setter: test), value: newValue, policy: .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }

    var test1: String {
        get {
            getAssociated(key: #selector(setter: self.test1)) ?? ""
        }
        set {
            setAssociated(key: #selector(setter: test1), value: newValue, policy: .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读