2011-12-06 130 views
1

我想下面的方法我用它來創建對象的批判:創建對象

在接口文件:

MyClass * _anObject; 
... 
@property (retain, nonatomic) MyClass * anObject; 

在實現文件:

@property anObject = _anObject 

到目前爲止,這麼簡單。現在讓我們來替代默認的getter:

(MyClass *) anObject { 
    if(_anObject == nil) { 
     self.anObject = [[MyClass alloc] init]; 
     [_anObject dowWhateverInitAction]; 
    } 
    return _anObject; 
} 

編輯: 我原來的問題是關於只創建(而不是在整個生命週期)的對象,但我添加以下,這樣它不」 Ť通過關閉任何一個:

- (void) dealloc { 
    self.anObject = nil; 
} 

/EDIT

的工作的主要一點是,設置器吸氣劑的內部使用。我已經將它用於所有類型的對象(ViewController,其他類型等)。我得到的優點是:

  • 僅在需要時才創建對象。它使應用相當快 (例如,在應用中有6-7個視圖,只有一個在 開始創建)。
  • 我不必擔心在使用它之前創建對象......它會自動發生。
  • 我不必擔心第一次需要對象的位置......我只能訪問對象,就好像它已經存在一樣,如果不存在,它就會被創建爲新的。

問題:

  • 是否恰好是一個既定的模式?
  • 你看到這樣做的缺點嗎?
+2

很常見的模式,通常稱爲延遲初始化。 – omz

+1

你打開ARC嗎?如果你不這樣做,那麼就有內存泄漏。在用'self.anObject'語法將實例變量賦值給''[MyClass alloc] init]'後,你需要釋放你創建的對象。你在做什麼是大多數情況下推薦的模式。 –

+0

我個人不喜歡帶副作用的吸氣劑。是的,懶加載是常見的,但我完全不會使用它遍佈我的應用程序,但只能用於包含許多子視圖的視圖(已由UIViewController完成)。 – Till

回答

0

是的這是一個確定的模式。我經常使用這樣的懶惰實例來代替-init-viewDidLoad與一堆設置代碼混淆。如果由於-init中發生的事件而導致該對象最終被創建,我會將該值賦給實例變量,而不是使用合成的setter。

3

這種模式通常用作延遲加載技術,只有在第一次請求時才創建對象。

如果創建的對象需要大量的計算來創建,並且在時間緊急的情況下請求(在這種情況下,使用這種方法沒有意義),則此方法可能存在缺陷技術)。但是我會說,如果物體能夠快速創建,這是一個足夠合理的事情。

+0

延遲加載通常不會在時間緊急的情況下完成,在時間緊張的情況下,您希望*預加載*和*緩存*,而不是延遲。延遲加載通常用於其他情況,即當某些事情需要一段時間才能加載但並非總是需要時。 – dreamlax

+1

是的,這是我的觀點,你不會在時間緊急的情況下使用這種技術。我會編輯我的答案,以便更清楚一點。 – Stuart

2

你的實現唯一的問題是(假設你還沒有使用ARC)是你有內存泄漏 - 使用setter意味着你的MyClass實例被過度保留。在初始化之後,您應該釋放或自動釋放_anObject,或直接分配它的值而不是調用setter。

除此之外,這是非常好的,當MyClass是一個不一定需要馬上需要並且可以很容易重新創建的對象時,這是一個很好的模式:您對內存警告的響應可以包括self.anObject = nil到釋放實例的內存。

2

它看起來像一個體面的lazy initialization。在哲學上,人們可以爭辯說缺點是吸氣劑有副作用。但副作用是不可見的,它是一種既定模式。

2

懶惰實例化是一種已建立的模式,Apple在其可怕的核心數據模板中使用它。

其主要缺點是過於複雜且通常不必要。我已經失去了我看到過的次數,在初始化父對象時僅僅實例化對象會更有意義。

如果一個簡單的解決方案是一樣好,請使用更簡單的解決方案。當父對象被初始化時,爲什麼不能實例化這些對象是否有特殊的原因?也許這個子對象佔用大量內存,而且很少被訪問?是否需要大量的時間來創建對象,並且在應用程序的時間敏感部分中初始化父對象?然後隨意使用懶惰的實例。但大多數情況下,您應該更喜歡更簡單的方法。

它也不是線程安全的。

關於你的優點:

需要當一個對象只被創建。它使應用程序非常快速(例如,應用程序中有6-7個視圖,只有一個在開始時創建)。

你指的是視圖還是視圖控制器?您的陳述與意見沒有任何意義。我通常不會發現自己需要將視圖控制器存儲在實例變量/屬性中,當我需要切換到它們並將它們推送到導航堆棧時,我將它們實例化,然後在完成時彈出它們。

您是否嘗試過不使用此模式的應用程序?關於表現的猜想常常是錯誤的。

我不必擔心在使用對象之前創建對象......它會自動發生。

不,現在你不用擔心編寫一個特殊的getter。這比簡單的實例化更復雜,更容易出錯。它也使您的應用程序邏輯和性能更難於理解和推理。

我不必擔心第一次需要對象的位置......我只能訪問對象,就好像它已經存在一樣,如果不存在,它就會被創建爲新的。

在父對象的初始化過程中實例化它時,您不必擔心。

+0

+1完全同意每一點。 – Till

+1

線程安全/原子性可以像使用任何其他手動執行的getter一樣簡單地通過'@ synthesis'實現。另外,懶加載並不真的太複雜,我根本沒有發現它太複雜。即使只看5行代碼,也不難看出發生了什麼。一個簡單的'/ /只有當使用'註釋作爲提示不會造成任何傷害,如果你認爲它會使它更容易理解。 – dreamlax

+1

並非所有這些都是非常主觀的,而且是一種風格和偏好的問題?我個人認爲它完全像Jim一樣行事,但我理解你的觀點@dreamlax。 – Till