Item 7 訪問數(shù)據(jù)_和.注意項
access變量時的在內(nèi)部直接訪問的區(qū)別,先看一個例子:
//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實例變量,用到了屬性的.表達式,假設(shè)你這樣重寫這兩個方法直接access實例變量:
- (NSString *)fullName{
return [NSString stringWithFormat:@"%@%@",_fistName,_lastName];
}
-(void) setFullName:(NSString *)fullName{
NSArray * components = [fullName componentsSeperateByString:@" "];
_firstName = [components objectAtIndex:0];
_latsName = [components objectAtIndex:1];
}
倆中方法區(qū)別:
直接訪問速度上肯定會快些,因為不需要調(diào)用oc方法
直接訪問繞過了屬性的
setter內(nèi)存管理語法,例如如果你的屬性定義為copy,直接設(shè)置實例變量不會生成一個copy,新值被保留,舊值被釋放掉KVO 通知不會失效, 還不懂KVO
通過
accessor來access屬性在調(diào)試時會容易些,可以直接設(shè)置setter getter 斷點
在初始化方法中設(shè)置值時,通常應該使用直接access的方式, 假設(shè)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設(shè)置為空,如果通過setter方法設(shè)置的,那么會調(diào)用到子類的setter方法,并且拋出異常。當然,有些情況如實例變量在父類中聲明的,你不能直接access到實例變量,你必須使用setter。
在使用lazy 初始化時,則必須通過getter 來access變量,如果不通過getter,實例變量可能沒有機會初始化。例如EOCPerson可能有一個屬性brain,如果這個屬性經(jīng)常被訪問到,但是設(shè)置值可能帶來很重的開銷,你可以在getter中延遲初始化這個值:
-(EOCBrain *) brain {
if(!_brain){
_brain = [Brain new];
}
return _brain;
}
如果直接訪問brain可能getter還沒有調(diào)用,brain可能就還沒設(shè)置好。
總結(jié)
- 建議內(nèi)部訪問時通過直接讀取實例變量(以
_方式訪問),設(shè)置變量值時通過setter - 在初始化方法和
dealloc中,讀寫最好通過_方法 - 某些場景(如
lazy)讀數(shù)據(jù)建議通過getter方法