2011-06-02 33 views
1

是一名Cocoa/Obj-C新手我正在瀏覽Aaron Hillegass的「Cocoa Programming for Mac OS X」一書,以及 - 現在我們還有機會使用GC來避免所有這些推理 - 我不確定我是否可以找到其中一些保留的原因。另一個「保留,然後釋放」的問題

尤其是在的例子亞倫給出良好的編程習慣之一:

- (void) setFoo:(NSCalendarDate *)x 
{ 
    [x retain]; 
    [foo release]; 
    foo = x; 
} 

我不明白的原因,在方法的第一行保留X實例:

[x retain]; 

這個實例的範圍只是set方法,對吧? 退出方法範圍時,x實例應該被釋放嗎? 此外,分配X時,與富貴:

foo = x; 

富無論如何都會被指向X存儲器單元,因此將增加尖銳的物體保留計數,不是嗎?這應該確保內存不會被釋放。

那麼,有什麼意義呢?我相信我錯過了一些東西,當然,但不知道究竟是什麼。

感謝, 法布里奇奧

+0

在附註中,這裏的代碼實際上突出了一個很好的練習。在某些情況下,'x'和'foo'可能已經指向同一個對象。在這種情況下,如果遵循'[foo release]'的典型設置流程,那麼foo = [x retain]',那麼您先釋放'x'/'foo',然後再保留它。如果在調用'setFoo:'時對象的保留計數爲'1',那麼它意味着'x'/'foo'首先被處理,然後被處理的對象被傳遞'retain'消息。繼Aaron的流程之後,在釋放'foo'之前先保留'x',避免了這個問題。 – 2011-06-22 07:15:01

回答

11

保留手段:我會需要這個對象呆在身邊,它不能被釋放。如果x不會被保留,下面是可能發生的:

分配xfoo,所以foo現在指向您的NSCalendarDate是地址。有人釋放或autoreleases這個對象,它的保留計數最終降到0,並且對象被釋放。現在您的foo仍然指向該地址,但不再有效的對象。過了一段時間,創建了一個新對象,偶然它位於與舊的NSCalendarDate對象相同的地址。現在您的foo指向一個完全不同的對象!

爲了防止這種情況,您需要retain它。你需要說,請不要釋放對象,我需要它。一旦你完成它,你release這意味着我不再需要的對象,你可以現在清理它,如果沒有人需要它。

現在爲經典的三部分作業。考慮你setFoo:應該是這樣的:

- (void) setFoo:(NSCalendarDate *)x 
{ 
    [foo release]; 
    [x retain]; 
    foo = x; 
} 

這是一個非常糟糕的主意。考慮你的對象是唯一一個保留了NSCalendarDate對象的人,然後考慮你會這樣做:[self setFoo:foo];。可能聽起來很愚蠢,但是這樣的事情可能會發生。該流程現在會是這樣:

  1. foo將被釋放。其保留計數現在可能會降至0,並且對象將被釋放。
  2. 哎呀,我們試圖保留並訪問一個釋放對象。

這就是爲什麼你總是先用retain這個新對象,然後release這個舊對象。

如果你從一個Java或.NET背景的人,這是非常重要的一點是Foo *類型的變量只包含你的對象,僅此而已的地址。在Java或.NET中,如果您願意,指向對象的變量會自動「保留」它。 Objective-C中並非如此(在非GC環境中)。您可以考慮將Foo *類型的變量視爲弱引用,並且您明確需要告訴Objective-C您是否仍然需要該對象在該地址。

+0

謝謝你的好解釋DarkDust清除了人類的疑惑,但是我可能沒有在我的問題中明確表達的唯一觀點是:不是'foo = x;'行將增加對象x點的保留數無論如何...?這就是爲什麼我認爲被迫保留是無用的... – 2011-06-02 11:34:03

+0

哦,我只是再讀一遍關於弱引用的最後部分!這是我的回答!我想知道爲什麼Aaron沒有用粗體字來指出......這與我習慣的其他語言有很大的不同。謝謝:) – 2011-06-02 11:44:12

+1

@Fabrizio Prosperi:也許亞倫沒有強調這一點,因爲他的背景。當他寫第一版時,.NET還不存在,Java還很年輕。大多數程序員都有C背景,或者Pascal或其他程序語言。唯一的注意力語言是LISP。對這些人來說,這個*變量賦值只會複製一個地址,並且不會做任何事情*行爲是絕對自然的,不需要解釋。只是隨着過去幾年GC驅動語言/環境的興起,這種情況發生了變化。 – DarkDust 2011-06-02 12:58:35

相關問題