在對象內部盡量直接存取執行個體變數 --Effictive Objective-C 抄書

來源:互聯網
上載者:User

標籤:

在對象之外訪問執行個體變數時,應該總是通過屬性來做.在那麼在對象內部訪問執行個體變數的時候,又該如何呢?

這是 OCer們一直激烈討論的問題.有人認為,無論什麼情況,都應該通過屬性來訪問執行個體變數;也有人說,”通過屬性訪問”和”直接存取”應該搭配著用. 除了幾種特殊情況之外, 筆者強烈建議大家在讀取執行個體變數的時候採用直接存取的形式,而在設定執行個體變數的時候通過屬性來做.

請看下面的類:

@interface EOCPerson : NSObject@property(nonatomic,copy)NSString *firstName;@property(nonatomic,copy)NSString *lastName;//設定全名的快捷方法-(NSString*)fullName;-(void)setFullName:(NSString*)fullName;@end

fullName和 setFullName這兩個”便捷方法”,可以這樣來實現:

-(NSString*)fullName{    return [NSString stringWithFormat:@"%@ %@",self.firstName,self.lastName];}/** *  下面的方法假設所有的全名有且僅有兩部分,當然這個方法也能被改寫,來支援外來姓名 */-(void)setFullName:(NSString *)fullName{    NSArray* components = [fullName componentsSeparatedByString:@" "];    self.firstName = [components objectAtIndex:0];    self.lastName  = [components objectAtIndex:1];}

在fullName的擷取與設定方法中,我們使用”點文法”,通過儲存方法來訪問相關執行個體變數. 假設重寫這兩個方法,不經由存取方法,而是直接存取執行個體變數:

-(NSString*)fullName{    return [NSString stringWithFormat:@"%@ %@",_firstName,_lastName];}-(void)setFullName:(NSString *)fullName{    NSArray *components = [fullName componentsSeparatedByString:@" "];    _firstName = [components objectAtIndex:0];    _lastName  = [components objectAtIndex:1];}

這兩種寫法有幾個區別:

  • 由於不經過 OC的 方法派發( method dispatch ),所以直接存取執行個體變數的速度當然比較快. 在這種情況下,編譯器所產生的程式碼會直接存取對象執行個體變數的那塊記憶體.

  • 直接存取執行個體變數時,不會調用其設定方法. 這就繞過了為相關屬性所定義的”記憶體管理定義”.比如,在ARC下直接存取一個聲明為 copy的屬性,那麼並不會copy該屬性,只會保留新值並釋放舊值.

  • 如果直接存取執行個體變數,就不會觸發 KVO通知,這樣做是否會產生問題,還取決於具體的對象行為.

  • 通過屬性來訪問有助於排查與之相關的錯誤,因為可以setter添加斷點,監控該屬性的調用者以及訪問時機.

有一種合理的這種方案,那就是:在寫入執行個體變數時,通過其 setter來做,而在讀取執行個體變數的時候,直接存取之.這樣,就技能提高讀取操作的速度,又能監控對屬性的寫入操作.之所以要通過setter來寫入執行個體變數,其首要原因在於,這樣做能夠確保相關屬性的”記憶體管理定義”得以貫徹.但是,選用這種方法時,需要注意幾個問題.

第一個要注意的地方是,在初始化方法中,應該如何設定屬性值.這種情況下總是應該直接存取執行個體變數,因為子類可能會 覆寫(override)設定方法.
在上例中,假設EOCPerson有一子類叫做 EOCSmithPerson,這個類表示那些姓 Smith 的人.該子類可能會override lastName所對應的設定方法:

-(void)setLastName:(NSString *)lastName{    if (![lastName isEqualToString:@"Smith"]) {        [NSException raise:NSInvalidArgumentException format:@"Last name must be Smith "];    }    self.lastName  = lastName;}

在父類 EOCPerson的預設初始化方法中,可能會將姓氏設為空白字串.此時若是通過 setter方法來做,那麼調用的將是子類的設定方法,從而拋出異常.但是某些情況下有必須在初始化方法中調用該設定方法:如果待初始化的執行個體變數聲明在父類中,而我們又無法在子類中直接存取此執行個體變數的話,就需要調用 setter 了.

另一個要主要的問題是:懶載入.在這種情況下,必須通過 getter訪問屬性,否則執行個體變數就永遠不會初始化.比如,EOCPerson類也許會用一個屬性來表示人腦中的資訊,這個屬性所代指的對象相當複雜.由於此屬性不常用,而且建立成本較高,所以,我們會在 getter中對其進行懶載入.

-(EOCBrain*)brain{    if(!_brain)    {        _barin = [Brain new];    }    return brain;}

在這種情況下,如果沒有使用 getter 方法,而直接存取執行個體變數,則會看到沒有初始化的 brain ,所以說,如果使用了懶載入,就必須通過getter 來訪問brain屬性.

歸納:

  • 在對象內部讀取資料時候,應該通過執行個體變數來讀,而寫入資料是,則應該通過屬性來寫.

  • 在初始化以及 dealloc方法中,總是應該通過執行個體變數來讀寫資料

  • 有時會使用懶載入技術配置某些資料,這種情況下,需要通過屬性來讀取資料.

在對象內部盡量直接存取執行個體變數 --Effictive Objective-C 抄書

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.