這是以前版本的Objective-C運行時的工件。
本來@synthesize
用於創建存取方法,但運行時仍要求實例變量必須顯式實例:
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
人們會前綴及其實例變量從他們的性質區分開來(即使Apple不希望你使用下劃線,但這是另一回事)。您將該屬性綜合爲指向實例變量。但重點是,_qux
是一個實例變量,並且self.qux
(或[self qux]
)是發送到對象self
的消息qux
。
我們直接使用實例變量-dealloc
;使用訪問方法,而不是看起來像這樣(雖然我不建議這樣做,原因稍後我會介紹):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
這有釋放qux
,以及清零參考的作用。但是這可能會帶來不幸的副作用:
- 您可能最終會觸發一些意外通知。其他對象可能會觀察對
qux
的更改,當使用訪問器方法更改該對象時會記錄這些更改。
- (並非所有人都同意這一點:)清零指針作爲訪問者可能會隱藏您的程序中的邏輯錯誤。如果你曾經訪問過一個對象的實例變量後該對象已被釋放,你正在做一件嚴重錯誤的事情。但是,由於Objective-C的
nil
-messaging語義,您永遠不會知道,使用訪問器設置爲nil
。如果你直接發佈了實例變量而沒有清零引用,那麼訪問釋放對象會導致響亮的響應EXC_BAD_ACCESS
。
更新版本的運行時添加了除訪問方法外還綜合實例變量的功能。與這些版本的運行時,上述代碼可以被寫入省略實例變量:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
這實際上合成上Foo
一個實例變量稱爲_qux
,其通過獲取和設置消息-qux
和-setQux:
訪問。
我推薦這樣:它有點混亂,但有一個很好的理由使用下劃線;即防止意外直接接觸伊娃。如果你認爲你可以信任自己記住無論你是使用原始實例變量或存取方法,只是不喜歡這樣,而不是:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
然後,當你想直接訪問實例變量,只是例如qux
(其在C語法中轉換爲self->qux
以從指針訪問成員)。當你想使用訪問器方法(它會通知觀察者,並做其他有趣的事情,並使內存管理更安全和容易),請使用self.qux
([self qux]
)和self.qux = blah;
([self setQux:blah]
)。
這裏最令人難過的是蘋果的示例代碼和模板代碼很糟糕。切勿將其用作正確的Objective-C風格的指南,並且絕對不要將其用作適當軟件體系結構的指南。 :)
沒有爲'@合成QUZ = _quz一個很好的理由; ';它意味着'self.quz'意思是消除了'quz'的意外寫入,反之亦然。編譯器問題相對較短,但真實。如果您發現有borked的示例,請提交bug。 – bbum 2011-03-29 01:11:41
@bbum好點再下劃線命名。我通常相信自己要打出正確的東西(或者如果我搞砸了,至少可以解決它),但是在制定編碼風格時,這肯定是需要思考的問題(我傾向於在美學方面犯錯誤,但它完全有效傾向於防止事故)。 – 2011-03-29 05:58:03
如果你不想手動編寫所有的樣板文件,你可能需要使用https://github.com/holtwick/xobjc(無恥的自我宣傳的開源項目;))它支持前導和尾部下劃線。 Google Styleguide爲ObjC推薦了後面的內容。這也很有用,因爲Apple在自己的代碼中也使用了前導下劃線,所以在極少數情況下您可能會遇到私有API的麻煩。 – Holtwick 2011-03-29 08:21:30