首页 > ios > 第6条:理解“属性”这一概念(3)

第6条:理解“属性”这一概念(3)

  在实现这个自定义的初始化方法时,一定要遵循属性定义中宣称的“copy”语义,因为“属性定义”就相当于“类”和“待设置的属性值”之间所达成的契约。初始化方法的实现代码可以这样写:

- (id)initWithFirstName:(NSString*)firstName lastName:(NSString*)lastName
{
if ((self = [super init])) {
_firstName = [firstName copy];
_lastName = [lastName copy];
}
return self;
}

  读者也许会问:为何不调用属性所对应的“设置方法”呢?如果用了“设置方法”的话,不是总能保证准确的语义吗?笔者在第7条中将会详细解释为什么决不应该在init(或dealloc)方法中调用存取方法。
  要是看过第18条的话,你就会明白,应该尽量使用不可变的对象。如果将这一条套用到EOCPerson类身上,那就等于说,其两个属性都应该设为“只读”。用初始化方法设置好属性值之后,就不能再改变了。在本例中,仍需声明属性的“内存管理语义”。于是可以把属性的定义改成这样:

@property (copy, readonly) NSString *firstName;
@property (copy, readonly) NSString *lastName;

  由于是只读属性,所以编译器不会为其创建对应的“设置方法”,即便如此,我们还是要写上这些属性的语义,以此表明初始化方法在设置这些属性值时所用的方式。要是不写明语义的话,该类的调用者就不知道初始化方法里会拷贝这些属性,他们有可能会在调用初始化方法之前自行拷贝属性值。这种操作是多余而且低效的。
  atomic与nonatomic的区别是什么呢?前面说过,具备atomic特质的获取方法会通过锁定机制来确保其操作的原子性。这也就是说,如果两个线程读写同一属性,那么不论何时,总能看到有效的属性值。若是不加锁的话(或者说使用nonatomic语义),那么当其中一个线程正在改写某属性值时,另外一个线程也许会突然闯入,把尚未修改好的属性值读取出来。发生这种情况时,线程读到的属性值可能不对。
  如果开发过iOS程序,你就会发现,其中所有属性都声明为nonatomic。这样做的历史原因是:在iOS中使用同步锁的开销较大,这会带来性能问题。一般情况下并不要求属性必须是“原子的”,因为这并不能保证“线程安全”(thread safety),若要实现“线程安全”的操作,还需采用更为深层的锁定机制才行。例如,一个线程在连续多次读取某属性值的过程中有别的线程在同时改写该值,那么即便将属性声明为atomic,也还是会读到不同的属性值。因此,开发iOS程序时一般都会使用nonatomic属性。但是在开发Mac OS X程序时,使用atomic属性通常都不会有性能瓶颈。

要点

  可以用@property语法来定义对象中所封装的数据。
  通过“特质”来指定存储数据所需的正确语义。
  在设置属性所对应的实例变量时,一定要遵从该属性所声明的语义。
  开发iOS程序时应该使用nonatomic属性,因为atomic属性会严重影响性能。

  1. 还没有评论
评论提交中, 请稍候...

留言


可以使用的标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Trackbacks & Pingbacks ( 0 )
  1. 还没有 trackbacks