使用Runtime给Category添加属性。
Category 与 property
我为类ViewController
添加了一个Category
,然后我想给他添加一个属性,vcName
于是我在ViewController+Category
中声明了一个属性
|
|
我们知道在类目的接口中是可以声明属性的。但是在他的实现部分是不允许包含@synthesize
的。 下面安利一下两个关键字@synthesize
、@dynamic
@synthesize
的语义是如果我们没有手动的实现property
的setter
和getter
方法,编译器会自动的添加上这两个方法。@dynamic
告诉编译器,属性的setter
与getter
方法由用户自己实现,不自动生成。在平常我们都习惯了不写这两个关键词,这个时候其实默认是
@synthesize var = _var
回到刚才的地方,如果我手动加上@synthesize vcName = _vcName;
是无法通过编译的。
|
|
如果我不写的话编译器会有警告让你加上@dynamic
语句。这个当然也是不行的。因为这个时候我自己写setter和getter.
|
|
这时候编译器会报错
|
|
结论
Categoryde 的接口中可以包含属性声明,但是实现部分不能包含
@synthesis
给Category 添加 Property
已经有了上面的结论了,但是我们在具体开发过程中确实会遇到很多需要在类别中添加使用Property
的情况。这个时候应该怎么办呢?我们知道Obj-c是一门动态语言,强大的运行时(Runtime)机制能够为类关联引用,然后通过这种方法来实现给类别添加属性。
关联引用指的是借助运行时功能,为已存在的对象增加实例变量。
通过关联引用就算时同一个类的不同对象也可能添加关联或者添加不同种类和数量的关联。另外添加了的关联也是可以被删除的。
添加和检索关联
既然说到了需要使用runtime,那我们首先需要导入Runtime相关的头文件
|
|
|
|
|
|
这一个的原理还是比较简单的。
首先,我们需要为一个类别专家多个关联引用,所以我们需要用不同的key值来区别。
其次,键值必须要使用一个确定且不可变的地址。所以选择定义在实现文件的static静态局部变量的地址。
policy策略就跟定义property的时候才用的存储关键字相似了。
存储关键字
第四个参数objc_AssociationPolicy policy
其实是一个枚举,点看之后我们可以看到
|
|
有这5个值
下面就分别的介绍一下几种。看注释也知道:
OBJC_ASSOCIATION_ASSIGN weak
不给关联对象发送retain
消息,引用计数不会增加。
OBJC_ASSOCIATION_RETAIN_NONATOMIC strong
发送retain
消息,引用计数加1. 如果给同样的key关联到了其他对象,那么会给其他对象发送一个release
消息。释放关联对象的所有者的时候,会给所有关联的对象发送release
消息。
OBJC_ASSOCIATION_COPY_NONATOMIC copy
会将该对象复制一份,并且用新复制的对象进行关联操作。
OBJC_ASSOCIATION_RETAIN strong
、atomic
OBJC_ASSOCIATION_COPY copy
、atomic
断开关联
runtime 也贴心的提供了断开关联的函数。但是可惜,我并不经常用,因为使用上面的方法并且传入nil来断开关联,会更佳安全,毕竟,我不敢保证是不是有其他地方会使用到已经关联的对象。
|
|
代码
扯了这么多有的没得,还是talk is cheap, show me the code 比较好一点。
第一步 导入头文件
|
|
第二步 定义用作键值的静态变量。
|
|
第三步 定义存取方法
|
|
试一下断开关联
首先在category中定义两个关联属性
在vievcontroller中给两个属性赋值,并且给self.title
赋值
然后用objc_removeAssociatedObjects(self);
断开关联
然后输出结果,category中关联的属性两个都输出null
而本身的属性title正常输出
结论
很好说了,objc_removeAssociatedObjects(self);
的作用是断开所有关联。
而且也更简单的验证了,使用runtime给对象关联的属性跟本身的属性本质是是不一样的。