众所周知, 在Swift的扩展(Extension)中只能添加计算属性, 但是有时候, 我们需要添加存储属性的话, 就用到了Runtime的方法.
在为Extension添加存储属性的时候, 主要用到了下面两个方法:
public func objc_setAssociatedObject(_ object: Any, _ key: UnsafeRawPointer, _ value: Any?, _ policy: objc_AssociationPolicy)
public func objc_getAssociatedObject(_ object: Any, _ key: UnsafeRawPointer) -> Any?
介绍
objc_setAssociatedObject 参数
存储属性
参数1( object ) : 要添加属性的类
参数2( key ): 指定存储的key, 需要使用取址运算符&(参考下面示例)
参数3( policy ): 参数属性, 是个枚举, 根据不同的数据类型选择
objc_getAssociatedObject 参数
读取属性
参数1( object ) : 要添加属性的类
参数2( key ): 指定存储的key, 需要使用取址运算符&(参考下面示例)
objc_AssociationPolicy 类型
public enum objc_AssociationPolicy : UInt {
/**< Specifies a weak reference to the associated object. */
case OBJC_ASSOCIATION_ASSIGN
/**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
case OBJC_ASSOCIATION_RETAIN_NONATOMIC
/**< Specifies that the associated object is copied.
* The association is not made atomically. */
case OBJC_ASSOCIATION_COPY_NONATOMIC
/**< Specifies a strong reference to the associated object.
* The association is made atomically. */
case OBJC_ASSOCIATION_RETAIN
/**< Specifies that the associated object is copied.
* The association is made atomically. */
case OBJC_ASSOCIATION_COPY
}
示例:
以为UIView添加扩展为例
var myNameKey = 100
var myAgeKey = 101
var myOptionKey = 102
extension UIView {
var myName: String {
set {
objc_setAssociatedObject(self, &myNameKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
if let rs = objc_getAssociatedObject(self, &myNameKey) as? String {
return rs
}
return ""
}
}
var myAge: Int {
set {
objc_setAssociatedObject(self, &myAgeKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
}
get {
if let rs = objc_getAssociatedObject(self, &myAgeKey) as? Int {
return rs
}
return -1
}
}
var myOption: UILabel? {
set {
objc_setAssociatedObject(self, &myOptionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &myOptionKey) as? UILabel
}
}
}
上面为UIView添加了三个不同类型的属性, 在使用的时候, 就可以正常的进行赋值/取值:
let view = UIView()
// 赋值
view.myAge = 100
view.myName = "扩展的存储属性"
view.myOption = UILabel()
// 取值
print(view.myAge)
print(view.myName)
print(view.myOption)
输出:
100
扩展的存储属性
Optional(<UILabel: 0x7fb863d10bf0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x600000289970>>)