可以给Category(或者 Swift中类的拓展)添加成员变量么?
这是一个经典的面试题. 通过源码, 我们可以很直观的看到, 分类的结构体 category_t 并没有 ivas 成员变量, 所以我们不可以直接给Category 添加成员变量
但是 category_t 中有 属性列表 properties, 那么也就是说可以给属性添加属性, 但是这跟本来的属性有什么区别呢?
本类中的属性, 编译器会自动帮我们生成setter和getter方法, 但是Category中的属性并不会, 所以当在Category我们声明了一个属性, 在给属性赋值时, 就会报错。
所以, 这就需要我们自己手动给分类的属性添加setter和getter方法. 但是分类又不能添加成员变量, 那么我们的setter方法给谁赋值? getter 又返回谁? 下面我们以Swift 类拓展添加关联对象做举例。
关联对象技术
我们可以通过关联对象间接给一个Swift的类拓展添加一个类似成员变量的东西. 关联对象相关有三个主要的函数
/** 给一个对象设置关联对象
object: 需要添加关联的源对象
key: 关联值的唯一key
value: 关联的具体值
policy: 关联的策略 (类似声明properties的参数)
*/
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
/** 获取某个对象的某个关联对象
object: 需要获取关联的源对象
key: 关联值的唯一key
*/
id objc_getAssociatedObject(id object, const void *key)
/** 移除对象的关联对象
object: 需要移除的源对象
*/
void objc_removeAssociatedObjects(id object)
通过关联对象技术, 我们可以在setter方法中, 给 cName 赋值, 在getter方法中获取 cName 的值
代码举例(给UIButton的拓展添加一个count属性)
extension UIButton {
private static var ADJ_KEY: Void?
var count: Int {
get {
(objc_getAssociatedObject(self, &Self.ADJ_KEY) as? Int) ?? 0
}
set {
objc_setAssociatedObject(self, &Self.ADJ_KEY, newValue, .OBJC_ASSOCIATION_COPY)
}
}
}
使用
override func viewDidLoad() {
super.viewDidLoad()
let test = UIButton()
test.count = 200
print(test.count)
}
文章持续更新中、希望对各位有所帮助、有问题可留言 大家共同学习.
网友评论