iOS开发中利用runtime为某个类的category增加属性
这篇文章中给出了为分类“添加成员变量”的代码,实际用到的就是关联对象,方法是runtime中的API,至于“添加成员变量”为什么是带引号的,下面我们进行解释。
看代码:
@interface Person (property)
@property (nonatomic, copy) NSString * name;
@end
现在有一个Person类以及它的一个分类,在分类中我们增加一个name属性。
我们知道如果name这个属性直接添加在Person类中,name会自动为Person类添加一个_name成员变量和其对应的set、get方法的声明和实现,但在分类中 @property (nonatomic, copy) NSString * name;这行代码实际上
只生成了set、get方法的声明,既没有set、get方法的实现也没有成员变量_name的添加。分类中是不能直接添加成员变量的。(不能添加属性的原因)
为了在分类中达到添加成员的目的,我们需要自己去实现set、get方法,看代码:
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self, _cmd);
}
set方法中我们是使用了runtime中的API设置关联对象,get方法中我们是使用了runtime中的API获取关联对象。
解释“添加成员变量”带引号
使用关联对象这种方式虽然在外部看似乎就是添加了成员变量,但关联对象并没有被添加到被关联的对象中即在Person类对象中的成员变量中并没有name这个成员变量。
关联对象存储在哪里呢?
看图,关联对象存储在全局统一的一个AssociationManager中。
设置关联对象方法中的object参数做为键对应一个map,在map中key参数做为键对应一个ObjectAssociation,在ObjectAssociation中存放着value参数和policy参数。
OBJC_ASSOCIATION_COPY_NONATOMIC参数
解释一下设置关联对象中的OBJC_ASSOCIATION_COPY_NONATOMIC这个参数,这个参数是和添加的属性的修饰符号相对应的。看图:
分类不能直接添加属性,苹果为什么要这样设计?
如果基类动态增加成员变量会导致所有已创建出的子类实例都无法使用。
方法定义是在objc_class中管理的,不管如何增删类方法,都不影响类实例的内存布局。