2009-08-26 25 views
5

在Objective-C中,這一點語法對我來說有點混亂。Objective-C:什麼時候調用self.myObject vs只調用myObject

什麼時候應該調用self.myObject vs只調用myObject?

它似乎是多餘的,但它們不可互換。

有人請賜教嗎?

+0

我在這裏找到了一個類似的帖子:http://stackoverflow.com/questions/1051543/should-i-use-self-keyword-properties-in-the-implementation – Jonah

回答

8

如果你只是訪問它們,沒有太多的理由使用self.member。如果你在做任務,那麼如果你做的不僅僅是簡單的@property (assign)參數,比如保留,複製等,這樣可以節省你寫的代碼。舉個例子:

myObject = anotherObject; 
self.myObject = anotherObject; 

第二種選擇將確保你實際上是分配對象,你想要的方式(獲得一個副本,增加了保留計數,等等)。這與[self setMyObject:anotherObject]沒有什麼不同。由於編譯器使用點符號代替消息(類似於x[5]在常規數組工作中變爲*(x + 5*sizeof(x))),因此在常規消息上使用點符號沒有任何開銷或額外的效率。

1

您幾乎從不應該在同一個類的實現中調用屬性訪問器。類的實例方法可以方便地訪問內部狀態,因此通常直接訪問該狀態是有意義的。

如果您正在使用合成的accesors,那麼調用它們只會增加(可能)不必要的開銷。如果訪問器有更復雜的實現,那麼你只是模糊了代碼的目的。

最後,一些新來Objective-C的人使用self.property語法和合成訪問器來嘗試避免理解Cocoa內存管理。你確實需要了解它是如何工作的,所以試圖避免這樣做會適得其反。

+0

只是因爲你可以擺弄對象的內部狀態所有這些並不意味着你應該這樣做。只是因爲你明白內存管理的工作方式並不意味着你會在所有的團隊中完成它。在一堆方法中重複你的內存管理責任就是要求bug。 – Chuck

+0

我恭敬地不同意。如果你的班級有很多@綜合訪問者,那麼他們的設計可能很差。如果你已經實現了不重要的訪問器,那麼你應該小心使用它們。 屬性訪問器旨在用於爲您的類創建* external *接口。有時候,你的班級在內部使用它的外部接口是有意義的,但通常這是不必要的(或反作用)。 –

+0

無論如何,如果你真的想使用訪問器,那麼使用「自我」。語法只是掩蓋了正在發生的事情,所以您應該使用顯式消息。如果你正在設置一個屬性,「[self setFoo:value]」只比「self.foo = value」長5個字符。對於讀取訪問,差異更小。 你只會編寫一次代碼,所以你應該試着讓你更清楚當你(或其他人)稍後閱讀時發生了什麼。 –

1

如果您使用的是核心數據,您應該基本上總是使用訪問器,因爲有些屬性可能不會從持久存儲中加載直到需要。如果你不使用核心數據(假設你正在使用一個SQLite店,反正。)

,你通常是安全的,只需使用myObject直接,如果你只閱讀值。如果您要修改myObject的值,則需要使用訪問器以確保任何其他觀察該屬性值的對象都得到了正確通知。換句話說:

// Not changing the value of myObject, so no accessor needed 
[someMutableArray addObject:myObject]; 

// Changes the value, so you need to use the accessor 
self.myObject = newObject;  
[self setMyObject:newObject]; // Exactly identical to the previous line. 

總的來說,這裏的開銷很小;我更喜歡總是使用訪問器,即使在同一個對象內。 (當然,在初始化程序中使用它們有爭論,但這是一個單獨的問題。)

3

Hrm,我不能說我同意Mark或Cinder6。

那麼,我同意第一部分。 :-) self.foo正在調用-foo方法。 Plain foo正在訪問foo ivar。

在大多數情況下,你應該經常瀏覽你的方法。他們在那裏將您從實際存儲中抽象出來,遠離可能需要的其他任何行爲。想想如果你以後再上課你會發生什麼。大多數情況下,您希望在訪問其覆蓋的功能的地方調用您自己的公共方法。

唯一的例外是在對象初始化和拆除,並在屬性訪問自己,當你不合成它們。在對象初始化和拆卸過程中,你要做而不是想要調用方法的子類實現,因爲這些方法不應該在你的部分設置狀態下處理你的對象。

0

沒有切段,曬乾的答案。但是,請記住,過早優化是不好的。在Mac上的Cocoa或iPhone上,使用訪問器/屬性需要符合KVO標準。 Core Data和Cocoa Bindings自動運行需要KVO一致性。在覈心數據中,修改屬性時不僅需要確保KVO,而且還需要在訪問它們時確保KVO。

當您想要確保屬性內存管理行爲時,也就是說,在設置ivar時使用setter或dot符號,並根據您遵循的內存管理模式,最好使用訪問器/屬性,在獲得伊娃時總是使用訪問者/屬性。

有許多的不同的內存管理模式。所有未破壞的函數確保訪問器返回的對象至少能夠存活到當前自動釋放範圍的末尾。意思是,該對象在當前的自動釋放範圍內被明確保留並自動釋放。蘋果推薦的方法在吸氣明確地做到這一點:

- (id)foo {return [[foo retain] autorelease]; } 
- (void)setFoo:(id)aFoo { 
    if(! [aFoo isEqual:foo]) { 
    [foo release]; 
    foo = [aFoo retain]; 
    } 
} 

它暗示這是他們在合成存取遵循的模式。就個人而言,我更喜歡的setter自動釋放:

- (id)foo {return foo;} 
- (void)setFoo:(id)aFoo { 
    [foo autorelease]; 
    foo = [aFoo retain]; 
} 

這與新值替換它之前autoreleasees舊值。這與getter中的保留和自動釋放具有完全相同的效果,但要求該對象只能添加到autorelease池中一次。大多數情況下,保留數爲1,而不是自動釋放,所以無論發生什麼事情,它都不會去任何地方。如果在某些代碼中仍然保留屬性(例如在委託回調中),則該屬性將被替換,但它不會從它下面消失。

這意味着,使用存取/屬性會給你信心,當你需要他們沒有代碼的其他部分由下你釋放出來的對象將圍繞長。

總是使用訪問器/屬性的最後一個也是最好的理由是它使每個屬性的一個更少的假設:該屬性有一個基礎ivar,並且它具有相同的名稱(我猜這是兩個假設) 。也許將來你會想用派生的訪問器替換一個ivar。財產符號仍然有效。也許你想重新命名伊娃;該物業仍然有效。幸運的是,通常可以依賴Xcode中的重構,但爲什麼還要麻煩?

面向對象編程的點是使用的類定義的接口。沒有很好的理由(儘管有許多偏見和合理的理由)讓一個班級忽​​略自己的界面。在一般情況下,除訪問者本身之外的每種方法應該將對象視爲神聖不可侵犯,並將其內部狀態視爲私有。將每種方法寫成類別或子類,並將ivars視爲私有狀態,除非特定的設計需要指導您做其他事情。直接訪問ivars有很多很好的理由,但它們是根據具體情況確定的。

+0

您的getter/setter方法與Apple的方法不同。你的getter基本上是你用於「assign」屬性的那個,setter是用於「retain」屬性的。我相信它大部分時間都能正常工作,但我認爲如果你開始使用自己的autorelease池,它會變得不穩定。最好堅持在可可其餘部分使用的慣例。 –

相關問題