2009-07-27 95 views
2

我有一個多線程的iPhone應用程序中與內存管理相關的問題。 比方說,我們有這樣的方法,即所謂的在比主UI線程的一個單獨的線程:多線程iPhone應用程序崩潰與[NSAutoreleasePool發佈]

- (BOOL)fetchAtIndex:(NSUInteger)index 
{ 
    NSURL *theURL = [NSURL URLWithString:[queryURLs objectAtIndex:index]]; 
    // Pay attention to this line: 
    NSData *theData = [[NetworkHelper fetchFromNetwork:theURL] retain]; 

    // Some code here... 

    // Now what should I do before returning result? 
    //[theData release]; ?? 
    //[theData autorelease]; ?? 
    return YES; 
} 

正如你所看到的,我保留了NSData我從我的網絡操作的恢復。問題是:爲什麼我不應該在我的方法結束時釋放(或自動釋放)它? 我使它工作的唯一方法是首先使用retain,然後沒有。如果我使用任何其他組合(完全沒有; retain然後releaseautorelease),當我釋放線程的NSAutoreleasePool時,我的程序崩潰EXC_BAD_ACCESS。 我錯過了什麼?

僅供參考,這裏是線程的主要代碼:

- (void)threadedDataFetching; 
{ 
    // Create an autorelease pool for this thread 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    // Reload data in separate thread 
    [self fetchAtIndex:0]; 

    // Signal the main thread that fetching is finished 
    [self performSelectorOnMainThread:@selector(finishedFetchingAll) withObject:nil waitUntilDone:NO]; 

    // Release all objects in the autorelease pool 
    [pool release]; // This line causes EXC_BAD_ACCESS 
} 

感謝您的幫助!

回答

3

您不得釋放您自己未保留的東西(使用retain或使用init,newcopy的方法暗示其名稱)。

如果您保留fetchFromNetwork的結果,那麼您必須將其釋放。 releaseautorelease都應該工作(在release之後請勿觸摸對象,在release之後將字段/變量設置爲nil最安全)。

如果你不保存數據,那麼你甚至不需要保留它。 [NetworkHelper fetchFromNetwork]應該返回自動釋放對象。的fetchFromNetwork身體看起來是這樣的:

NSData *data = [[NSData alloc] init]; 
// stuff happens 
return [data autorelease]; 

NSData *data = [otherObject dataFromOtherObject]; 
// stuff happens 
return data; // don't (auto)release, since you haven't retained 

如果有疑問,寧可漏側並通過「泄漏」儀器或LLVM checker運行的應用程序。

+0

謝謝。 確實,fetchFromNetwork就像你的第二個代碼示例: NSData * data = [otherObject dataFromOtherObject]; ... return [data autorelease]; //錯了! 這就是爲什麼我必須保留在我的客戶端代碼。 我刪除了錯誤的-autorelease調用,然後在客戶端的--retain代碼,現在一切都很好。 謝謝! – Romain 2009-07-27 20:59:27

0

事實上,你在一個單獨的線程可能不相關在這裏。內存管理是一樣的,你應該平衡你的NSData的保留/釋放,就好像這是主線程一樣。在排除autorelease池時你崩潰的事實表明你可能已經在Data中做了一些你沒有在這裏展示過的東西(這很明顯,因爲所示的代碼不是很有用)。你在做什麼需要其他人保留它?

+0

你是對的,正如我在其他評論中寫的,fetchFromNetwork是autoreleasing的NSData對象,所以我_had_保留它在這個代碼,所以它的工作,但錯誤的部分是在fetchFromNetwork方法。 謝謝。 – Romain 2009-07-27 21:01:32

0

正如其他人已經指出的那樣,在這種情況下它是多線程並不實際相關。值得一讀的是蘋果公司生產的Objective C Memory Management Guidelines。粗略地說,你自己明確[[Foo alloc] init]的任何對象,你都應該負責清理。如果你從一個方法返回這個值,你也需要自動釋放它。

你從調用者獲得的任何不以initWith開頭的對象(如[Foo emptyFoo]),調用者有責任擁有該資源(即autorelease)。

如果您傳遞了一個對象並希望將其保留在方法調用之外(即,將其保存到實例字段中),您必須保留它。當你完成後,你通常在析構函數中釋放它。如果您使用Objective C屬性,將其定義爲@retain會自動爲您啓動此行爲;在析構函數中,您可以將屬性設置爲零。