2011-09-29 93 views
1

我正在學習如何編程,並從Objective C開始。我試圖準確理解當從一個方法內分配對象時會發生什麼。目標C:從方法返回對象

-(Fraction *) add: (Fraction *) f 
{ //'result' will store the result of the addition 

Fraction *result = [[Fraction alloc]init]; 

result.numerator = (numerator*f.denominator + denominator*f.numerator); 
result.denominator = denominator*f.denominator; 

[result reduce]; 
return result; 
} 

我知道我可以創建一個對象來存儲「結果」返回,當它在,

tempStorageObject = [aFraction add: bFraction]; 

的,我是那麼釋放它負責,但是當我穿上」發生了什麼t存儲它,如:

[aFraction add: bFraction]; 
NSLog(@"%i/%i", result.numerator, result.denominator); //result object not declared in main 

我被告知我有一個未聲明的標識符。我明白了,但是使用我的'add'方法後會發生什麼'結果'。它在哪裏?我應該不能訪問它的變量,因爲它是在方法中創建並返回的?顯然不是,但我不清楚爲什麼。我試過重新閱讀我的書並搜索這個論壇,但我找不到明確的答案。謝謝。 (第一篇文章)

回答

3

四種不同的東西:

  1. 屬性
  2. 局部變量
  3. 函數的返回值
  4. 堆存儲

「我知道這一點,但到底發生了什麼,以 '結果'在使用我的'add'方法之後,它到底在哪裏?「

這是一個局部變量。它消失了。

「我不應該能夠訪問它的變量」

看到你的評論,它看起來像你的意思是通過點符號訪問。不,點符號是屬性。

「因爲它創建」

點標記不給你訪問局部變量。

「並返回該方法?」

點符號不允許您訪問函數返回值。

所有前三件事都是指針,當它們指向對象時。第四件事是他們指出的。當您執行alloc時,您將在堆存儲中創建一個對象。然後您將實例變量,屬性,局部變量和函數返回值引用到堆存儲中。在某種程度上,您認爲它們與堆存儲中的對象相同。像點符號這樣的語法糖可以幫助您做到這一點。你的對象會持續下去,但在這種情況下,引用它的不同變量在範圍上是有限的,並且來來去去。

  1. 當你調用alloc時,會在堆上創建一個對象。

  2. 當您將其分配給結果時,結果現在具有相同的對象。

  3. 當您返回結果時,局部變量結果不再存在,返回值暫時保持相同的對象,並且該對象仍然存在於堆中。

4a。當你將函數結果分配給tempStorageObject,另一個局部變量(我猜)時,函數結果就會消失。它只是暫時地將函數內部的值傳遞出去。 tempStorageObject現在保存該對象,並且該對象仍然存在於堆中。

4b。相反,如果您不將函數結果賦值給任何東西,那麼函數結果仍會消失。但該對象仍然存在於堆上。你有個問題。你在堆上有一個對象,但是你不能直接在那裏引用它(除非你擅長猜測它的地址)。如果你不能指出它,你就無法把它從堆中拿出來,如果你反覆做這樣的事情,這將是一個主要問題。堆將開始充滿你無法擺脫的物體,並且你的內存不足。這就是所謂的泄漏。

在這種情況下要做的正確事情是return [result autorelease]。當您撥打[something autorelease]時,它會向「自動釋放池」添加「某物」,然後返回相同的內容。

  1. 你調用alloc並在堆上創建一個對象。其保留計數從1開始。

  2. 將其分配給結果,即局部變量。結果有對象,它在堆上。

  3. [result autorelease]。結果有對象,它在一個自動釋放池中,它在堆上。

  4. 返回。結果不見了,返回值有對象,它在autorelease池中,它在堆上。

5A。將返回值分配給tempStorageObject。返回值不見了,tempStorageObject有對象,它在一個自動釋放池中,並且它在堆上。

6a。您離開tempStorageObject的範圍。 tempStorage對象消失了。該對象位於自動釋放池和堆中。 5b)。

5b。您不會將函數結果分配給任何內容。功能結果消失了。該對象位於自動釋放池和堆中。

7ab。 autorelease池被排空。這通常是通過系統庫提供的主運行循環中的代碼完成的,但如果您知道如何執行,則可以自行完成。自動釋放池中的所有對象(包括我們正在關注的對象)都會發送一條釋放消息。對象的保留計數爲0.

8ab。保留計數爲0時,該對象將從堆中移除。該對象位於autorelease池中。

9ab。第二件事是從池中移除所有對象。現在該對象不再存在任何地方了。

+0

+1的真棒回答。 – esqew

1

你說你所熟悉的版本,所以我只是說你應該使用自動釋放關鍵字,它釋放分配的對象時,沒有更多的代碼塊需要它,請查看下面的文檔,從蘋果:

Memory Management Programming

+0

謝謝大道。我想我的問題不是「我如何釋放'返回'?」更重要的是,爲什麼我不能使用點符號來訪問它,因爲它是在'add'方法中創建和返回的。 –

+1

嗨** Kewigro **。我明白了。但是這樣做似乎是不可能的,因爲你在** result **中分配,這在** add **函數的範圍之外是不可訪問的。 – AVEbrahimi

1

頁頭的範圍是全球性的:一旦你分配一個對象,存在於內存空間,它和內存將保持分配直到釋放計數降爲零(或應用程序被終止)。在此之前,對象仍然存在。

變量的範圍要短得多。在你的例子中,'結果'在方法'add'的末尾超出了範圍。但是這個變量只是一個名字,是對一個對象的引用。所以無論誰打電話添加,都應該確保對返回的對象做些什麼。否則沒有更多的變量指向對象,所以它不能被釋放。

+0

謝謝克里斯。所以我不能在方法'add:'之外引用'result',因爲'result'的範圍僅限於方法本身。所以當我說'返回結果'時,我返回對象(分配內存)的引用而不是變量'result'?本質上,我的結果變量消失了,但分配的內存沒有,所以我需要將分配的內存'存儲'到主程序中的一個變量中。謝謝!! –