分类是不能合成属性的,因为合成属性会生成对应的实例变量,而分类是不允许添加实例变量的。
虽然不能添加实例变量,但是可以添加属性可以的。只不过需要自己在分类中实现set和get方法,同时标记属性为动态获取。
其中一种方法叫做关联引用,实现了用存取器来访问属性。当然实际上没有实例变量,所以本质上只不过增加了get和set 方法而已。
#import "Person+EmailAddress.h"
@implementation Person (EmailAddress)
static char emailKey;
- (NSString *)emailAddress {
return objc_getAssociatedObject(self, &emailKey);
}
- (void)setEmailAddress:(NSString *)emailAddress {
objc_setAssociatedObject(self, &emailKey, emailAddress, OBJC_ASSOCIATION_COPY);
}
@end
注意,关联引用是基于键的内存地址的,而不是值的。emailKey 中存着什么不重要,重要的是内存地址是不变的。这也是一般用未赋值的static char 变量作为键的原因。
总结:
- 我们知道category是不能创建实例变量的,但我们可以通过关联引用来达到这样的目的。特别是当你不持有这个类,比如说系统的类,而你又的确需要添加一个property。
- 用来标记是哪一个属性的key常见有三种写法,但代码效果是一样的,如下:
//利用静态变量地址唯一不变的特性
1、static void *strKey = &strKey;
2、static NSString *strKey = @"strKey";
3、static char strKey;
- 关联策略是个枚举值,解释如下:
enum {
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并且关联对象使用原子性
};