属性是什么?
属性所要表达的意思是:类中有数据在支持着它。属性是用来封装数据的。
属性只是定义实例变量及相关存取方法所用的”语法糖“,所以也应遵循同实例变量一样的规则。
为什么不能在分类中声明属性?
除了”class-continuation“分类之外,其他分类都无法向类中新增实例变量,因此,它们无法把实现属性所需的实例变量合成出来。
比方说你实现过一个表示个人信息的类,用分类机制将其代码分段。设计一个专门处理交友事务的分类,其中所有方法都与操作某人的朋友列表有关。如果把代表朋友列表的那项属性也放到Friendship分类里面:
@interface EOCPerson (Friendship)
@property (nonatomic, strong) NSArray *friends;
-(BOOL)isFriendsWith:(EOCPerson *)person;
@end
编译这段代码的时候,会发出警告,提示此分类无法合成与friends属性相关的实例变量,所以开发者需要在分类中为该属性实现存取方法。
如果开发者自己实现属性的存取方法,就会很容易出现错误的地方。比如,内存语义不一样,可变数组等问题。
并且分类的目标在于扩展类的功能,而非封装数据。
用什么方法可以解决在分类中不能合成实例变量的问题?
1、可以把存取方法声明为,也就是说,存取方法等到运行期再提供,编译器目前是看不见的。如果决定使用消息转发机制在运行期拦截方法调用,并提供其实现,那么或许可以采用这种方法。
2、关联对象能够解决在分类中不能合成实例变量的问题。比方说,我们可以在分类中用下面这段代码实现存取方法:
#import <objc/runtime.h>
static const char *kFriendsPropertyKey = "kFriendsPropertyKey";
@implementation EOCPerson (Friendship)
- (NSArray *) friends
{
return objc_getAssociatedObject(self, kFriendsPropertyKey);
}
- (void)setFriends:(NSArray *)friends
{
objc_setAssociatedObject(self, kFriendsPropertyKey, friends, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end