2011-09-02 25 views
1

我開始研究IOS開發,並對釋放對象的一些疑問,我沒有存儲引用..我看了一個問題「釋放沒有指針?」它建議在創建後立即發送自動釋放消息的對象,所以我試圖做同樣的在下面的一段代碼:錯誤自動釋放剛創建對象

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    NSURLResponse * response = nil; 
    NSError * error = nil; 
    NSData * data; 

    data = [NSURLConnection 
      sendSynchronousRequest: [[NSURLRequest requestWithURL: 
             [[NSURL URLWithString: @"http://www.google.it"] 
              autorelease] 
            ] autorelease] 
       returningResponse: &response 
          error: &error]; 

    [data writeToFile: @"/tmp/test.html" 
      atomically:NO]; 

    [data release]; 
    [pool drain]; 

    return 0; 
} 

我不能嘗試的XCode執行程序尚未,但我正在linux下編譯,發送給NSURLRequest對象的autorelease消息導致了一個分段錯誤(我認爲這不是由消息本身引起的,而是由於自動釋放消息導致嘗試釋放該對象的緩衝池) 。我發送給NSURLRequest對象的autorelease消息有什麼問題?

我認爲如果像requestWithUrl這樣的類方法的引用文檔說它「創建並返回一個URL請求」,這意味着我有責任在完成使用時釋放對象,我錯了?我希望在進一步研究其他任何事情之前理解這個內存管理規則。我希望我的問題不是太愚蠢;-)

呃,只是最後一個問題:我是否應該釋放錯誤和數據同步請求返回的對象?

非常感謝您的幫助!

回答

3

+requestWithURL:(和其他)方法已經返回autoreleased對象,所以你不應該再發送一個autorelease給他們。

您代碼中的額外autoreleases會使對象稍後過度發佈並導致應用程序崩潰。

經驗法則知道你是否必須釋放一個對象 - 只有當你使用包含'alloc','new','copy'的方法創建對象時才需要釋放它。所有的標準API遵循這個規則,你應該在開發你自己的方法時遵循它。

所以糾正代碼將是:

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    NSURLResponse * response = nil; 
    NSError * error = nil; 
    NSData * data; 

    data = [NSURLConnection 
      sendSynchronousRequest: [NSURLRequest requestWithURL: 
              [NSURL URLWithString: @"http://www.google.it"]                     
       returningResponse: &response 
          error: &error]; 

    [data writeToFile: @"/tmp/test.html" 
      atomically:NO]; 

    [pool drain]; 

    return 0; 
} 

附:由於上述原因,數據和錯誤對象都不應該被釋放。

+0

我想感謝大家的即時答覆!我懷疑它們是被自動釋放的,現在一切都變得更清楚了:如果我分配了一些我需要釋放的東西(或者將它標記爲稍後autorelease),如果我使用類方法創建實例,如+ requestWithUrl(不包含init /複製/新詞)我不應該釋放它,除非我保留它由於某種原因。 –

+0

@Gianni,正好! :) – Vladimir

1

您的代碼應該是這樣的:

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    NSURLResponse * response = nil; 
    NSError * error = nil; 
    NSData * data; 

    data = [NSURLConnection 
      sendSynchronousRequest: [NSURLRequest requestWithURL:[NSURL URLWithString: @"http://www.google.it"]] returningResponse:&response error: &error]; 

    [data writeToFile: @"/tmp/test.html" 
      atomically:NO]; 

    [pool drain]; 

    return 0; 
} 

你並不需要調用autorelease到與該方法創建你的對象\

你並不需要釋放dataerror

所有使用下一個符號NSClass *object = [NSClass classSomeMagicWords];返回對象的方法都會返回自動釋放對象,如果您不呼叫retain,則不應釋放該對象。

0

您應該刪除autoreleases。在iOS/Mac OSX開發中,通過Apple提供的類,幾乎所有的規則是,如果您使用不涉及init這個詞的方法創建對象,則會獲得一個已經自動釋放的對象。

例如:

NSString *blaah = [[NSString alloc] init]; 

會返回你以後需要釋放的對象。

NSURL *googlelink = [NSURL URLWithString: @"http://www.google.it"]; 

另一方面會給你一個自動釋放對象,如果你再次釋放它,它會崩潰。

0

在iOS內存管理中,只能通過爲其分配內存或複製它(方法要麼以alloc開頭,要麼使用其名稱中的「copy」)創建自己的對象。

你只需要釋放/ autorelease他們,如果你擁有它們。諸如requestWithURLURLWithString的方法已經返回自動釋放的對象。

從Apple開發人員站點查詢this doc以獲取更多信息。