你的位置:首页 > 操作系统

[操作系统]第26条:勿在分类中声明属性


属性是封装数据的方式(参见第6条)。

属性只是定义实例变量及相关存取方法所用的“语法糖”,所以也应遵循同实例变量一样的规则。

 

 

 

分类机制,应该将其理解为一种手段,目标在于扩展类的功能,而非封装数据。

 

 

尽管从技术上说,分类里也可以声明属性,但这种做法应该尽量避免。

原因是:除了“class-continuation分类”(参见第27条)之外,其他分类都无法向类中新增实例变量,因此,它们无法把实现属性所需的实例变量合成出来。

 

所以开发者需要在分类中为该属性实现存取方法。

1)此时可以把方法声明为@dynamic,也就是说,这些方法等到运行期再提供,编译器目前是看不见的。如果决定使用消息转发机制(参见第12条)在运行期拦截方法调用,并提供其实现,那么或许可以采用这种做法。

 

2)关联对象(参见第10条)能够解决在分类中不能合成实例变量的问题。

缺点:相似的代码要写很多遍,而且内存管理问题上容易出错。

例:

#import <objc/runtime.h>

static const char *kFriendsPropertyKey = "kFriendsPropertyKey";

@implementation Person(Friendship)

-(NSArray*)friends {

  return objc_getAssociatedObject(self, kFriendsPropertyKey);

}

-(void)setFriends:(NSArray*)friends {

  objc_setAssociaedObject(self, kFriendsPropertyKey, friends, OBJC_ASSOCIATION_NONATOMIC);

}

@end

 

3、只读属性可以在分类中使用。属性可以不需要由实例变量来实现。

由于只读属性在.m中只有一个getter方法,

即实现了该属性所需的全部方法,所以编译器不会再为属性自动合成实例变量。也就满足上面的条件了,编译器也就不会发出警告信息。

 

总结:

即便这3种方法可以实现,但不推荐。

而应该把封装数据所用的全部属性都定义在主接口里。

在“class-continuation分类”之外的其他分类中,可以定义存取方法,但尽量不要定义属性。