Swift中Associated Object使用
使用关联对象在扩展中增加实例字段。
需要定义一个本地变量(private var key: UInt8)用来取地址。
Swift Extension比Objective-C Category增色不少,extension能够给已有类添加计算型属性,但是仍不能添加存储属性。Swift中可以使用Objective-C的关联对象(Associated Objects)的方式添加属性,弥补这一痛点
Swift中提供3个与Objective-C类似的方法将自定义属性关联到对象上:
1、objc_setAssociatedObject
2、objc_getAssociatedObject
3、objc_removeAssociatedObjects
需要注意的是:objc_removeAssociatedObjects会删除对象关联的所有属性,所以可能导致把一些非自己添加的关联属性也删除掉。如果要删除某属性,使用objc_setAssociatedObject将value设置为nil即可
抽取关联对象方法
可以把关联对象的方法提取成公共方法,在NSObject类的extension里实现,只要继承子NSObject的类就能够调用关联对象方法,通过Swift泛型来关联不同类型的属性
extension NSObject{
func setAssociated(value: T, associatedKey: UnsafeRawPointer, policy: objc_AssociationPolicy = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) -> Void{
objc_setAssociatedObject(self, associatedKey, value, policy)
}
func getAssociated(associatedKey: UnsafeRawPointer) -> T? {
return objc_getAssociatedObject(self, associatedKey) as? T
}
}
在Swift中使用objc_setAssociatedObject和objc_getAssociatedObject时,调用setAssociated或getAssociated即可
extension UIView{
private struct AssociatedKeys{
static var displayName = “dispalyNameKey”
}
var displayName: String? {
get{
return getAssociated(associatedKey: &AssociatedKeys.displayNameKey)
}
set{
setAssociated(value: newValue, associatedKey: &AssociatedKeys.displayNameKey, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
}
在使用Swift Associated Object中需要注意的是:
1、嵌套私有结构体,声明与扩展属性对应的键(key),Swift Extension提供了丰富的功能,可以在Extension中嵌套类型,使用private私有访问控制,不会污染整个命名空间,而且能够统一管理关联对象键
2、Swift的基本类型Int,Float,Double,Bool能够自动隐式地转换成Objective-C的NSNumber,所以不需要显式的包装成NSNumber类型进行关联
3、如果使用OBJC_ASSOCIATION_ASSIGN关联策略时需要注意,文档中指出是弱引用,但不完全等同于weak,更像是unsafe_unretained引用,关联对象被释放后,关联属性仍然保留被释放的地址,如果不小心访问关联属性,就会造成野指针访问出错。
如果使用Associted Object关联闭包属性,则需要创建闭包容器
分以下两个步骤:
1、在extension中嵌套创建容器类,容器类中定义需要关联的闭包属性
2、关联对象时把容器类对象关联到已有类,间接的就把闭包属性关联到一有类
typealisa completionClosure = ()->()
extension UIViewController{
private struct AssociatedKeys {
static var completionKey = “completionKey”
}
class Container {
var completion: completionClosure?
}
var container: Container?{
get{
return objc_getAssociatedObject(self, &AssociatedKeys.completionKey)
}
set{
objc_setAssociatedObject(self, &AssociatedKeys.completionKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONTOMIC)
}
}
}
网友评论