Item 7 访问数据_
和.
注意项
access
变量时的在内部直接访问的区别,先看一个例子:
//convience methods
- (NSString *) fullName {
return [NSString stringWithFormat:@"%@%@", self.firstName,self.lastName];
}
- (void)setFullName:(NSString*)fullName{
NSArray * components = [fullName componentsSeperatedByString:@""];
self.firstName = [components objectAtIndex:0];
self.lastName = [components objecteAtIndex:1];
}
上例中,我们通过accessor
来access实例变量,用到了属性的.
表达式,假设你这样重写这两个方法直接access实例变量:
- (NSString *)fullName{
return [NSString stringWithFormat:@"%@%@",_fistName,_lastName];
}
-(void) setFullName:(NSString *)fullName{
NSArray * components = [fullName componentsSeperateByString:@" "];
_firstName = [components objectAtIndex:0];
_latsName = [components objectAtIndex:1];
}
俩中方法区别:
直接访问速度上肯定会快些,因为不需要调用oc方法
直接访问绕过了属性的
setter
内存管理语法,例如如果你的属性定义为copy
,直接设置实例变量不会生成一个copy,新值被保留,旧值被释放掉KVO 通知不会失效, 还不懂KVO
通过
accessor
来access属性在调试时会容易些,可以直接设置setter getter 断点
在初始化方法中设置值时,通常应该使用直接access的方式, 假设EOCPerson
有一个子类EOCSmithPerson
, 子类可能重写setter
方法:
- (void)setLastName:(NSString*)lastName{
if(![lastName isEqualToString @"Smith"]) {
[NSException raise:NSInvalidArgumentException format:@"Last name must be Smith"];
}
self.lastName = lastName;
}
基类EOCPerson
可能会在默认的初始化方法中把lastName
设置为空,如果通过setter
方法设置的,那么会调用到子类的setter
方法,并且抛出异常。当然,有些情况如实例变量在父类中声明的,你不能直接access到实例变量,你必须使用setter
。
在使用lazy
初始化时,则必须通过getter
来access变量,如果不通过getter
,实例变量可能没有机会初始化。例如EOCPerson
可能有一个属性brain
,如果这个属性经常被访问到,但是设置值可能带来很重的开销,你可以在getter
中延迟初始化这个值:
-(EOCBrain *) brain {
if(!_brain){
_brain = [Brain new];
}
return _brain;
}
如果直接访问brain
可能getter
还没有调用,brain
可能就还没设置好。
总结
- 建议内部访问时通过直接读取实例变量(以
_
方式访问),设置变量值时通过setter
- 在初始化方法和
dealloc
中,读写最好通过_
方法 - 某些场景(如
lazy
)读数据建议通过getter
方法