关于iOS分类:很多说法是只能添加方法,而不能添加成员变量或属性。有些人可能知道,这种说法是不严谨的,并不是绝对不能添加变量。 解释如下: 我们知道在一个类中用@property声明属性,编译器会自动帮我们生成_成员变量和setter/getter,但分类的指针结构体中,根本没有属性列表。所以在分类中用@property声明属性,既无法生成_成员变量也无法生成setter/getter。 因此结论是:我们可以用@property声明属性,编译会通过,但run之后就会崩溃。
那么问题来了。。 既然报错的根本原因是使用了系统没有生成的setter/getter方法,可不可以在手动添加setter/getter来避免崩溃,完成调用呢?其实是可以的。由于OC是动态语言,方法真正的实现是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法。那具体怎么实现呢?
举例如下: 分类.h
@interface CustomView (dd)- (NSString *)name;- (void)setName:(NSString *)name;@end复制代码
分类.m
@implementation CustomView (dd)/* * 使用关联对象模拟实例变量 * 使用objc_getAssociatedObject、objc_setAssociatedObject模拟『属性』的存取方法 */- (NSString *)name{ return objc_getAssociatedObject(self, _cmd); }- (void)setName:(NSString *)name{ objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }@end复制代码
重点就是两个runtime实现方法,如果不写这个,只要你申明了属性,运行肯定会报错;如果加了这两个方法,就能正常使用。 关联策略的解释如下:
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy){ OBJC_ASSOCIATION_ASSIGN = 0, //关联对象的属性是弱引用 OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //关联对象的属性是强引用并且关联对象不使用原子性 OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //关联对象的属性是copy并且关联对象不使用原子性 OBJC_ASSOCIATION_RETAIN = 01401, //关联对象的属性是copy并且关联对象使用原子性 OBJC_ASSOCIATION_COPY = 01403 //关联对象的属性是copy并且关联对象使用原子性};复制代码