2010-07-28 77 views
0

我有一個小iPhone應用程序,它在第一個視圖上有一個按鈕。當我選擇這個按鈕,我加載了我的新視圖,其上有一個圖像。我目前使用下面的代碼加載從一個單獨的線程在線源的圖像,同時允許用戶繼續控制應用:iPhone上的NSAutoreleasePool問題

- (void) loadImageTest 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSURL *url = [[NSURL alloc] init]; 
    url = [NSURL URLWithString:logoPath]; 

    NSData *data = [[NSData alloc] init]; 
    data = [NSData dataWithContentsOfURL:url]; 

    loadingImage = [UIImage imageWithData:data]; 
    titleLogoImage.image = loadingImage; 

    //[pool drain]; 
    [pool release]; 
} 

這是從在新視圖中的這行代碼中調用INIT:

[NSThread detachNewThreadSelector:@selector(loadImageTest) toTarget:self withObject:nil]; 

現在這工作正常(ISH),但如果我收了新的觀點,然後快速連續地重新裝入一個新的(或者只是後病房在某些情況下),它會彈了出來用傳統的EXC_BAD_ACCESS。我確信這是由於線程池中的代碼引起的,但任何人都可以看到爲什麼會發生這種情況?

謝謝

+0

殭屍會救你。 http://www.cocoadev.com/index.pl?NSZombieEnabled – 2010-07-28 22:46:22

回答

2

此致:

//這是確定的,你可以嘗試使用NSURLConnections,而不是把 //自己的線程異步方法。 [NSThread detachNewThreadSelector:@selector(loadImageTest)toTarget:self withObject:nil];

- (void)loadImageTest 
{ 
    // This is fine 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    // you're making and then abandoning this url object so it will leak 
    NSURL *url = [[NSURL alloc] init]; 
    // this is fine 
    url = [NSURL URLWithString:logoPath]; 
    // again making and abandoning an object 
    NSData *data = [[NSData alloc] init]; 
    data = [NSData dataWithContentsOfURL:url]; 
    // this works, but is not thread safe, 
    // can't operate on UIKit objects off the 
    // main thread 
    loadingImage = [UIImage imageWithData:data]; 
    titleLogoImage.image = loadingImage; 
    // this is fine 
    //[pool drain]; 
    [pool release]; 
} 

盪滌把事情線程安全的,等應該有所幫助:

// I'm assuming you have a iVar for logoPath but we don't want to 
// make threaded calls to an iVar (it's not mutable, so you could do it, but it's just bad form) 
// If i'm wrong about logoPath being an iVar don't sweat copying it. 
- (void)whateverMethodYouWant 
{ 
    NSString *aLogoPath = [[logoPath copy] autorelease]; 
    [NSThread detachNewThreadSelector:@selector(loadImageForPath:) toTarget:self withObject:aLogoPath]; 
} 
- (void)loadImageForPath:(NSString *)aLogoPath 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:aLogoPath]]; 
    // the performSelector will retain the data until the method can be performed 
    [self performSelectorOnMainThread:@selector(setImageForTitleLogo:) withObject:imgData waitUntilDone:NO]; 

    [pool release]; 
} 
- (void)setImageForTitleLogo:(NSData *)imgData 
{ 
    // This part is not strictly necessary 
    // but it's a nice way to wrap a method that needs to happen on the main thread. 
    if ([NSThread isMainThread]) 
    { 
     // make the image (i'm assuming you meant loadingImage to be a local scope variable) 
     UIImage *loadingImage = [UIImage imageWithData:imgData]; 
     // make sure the button still exists 
     // also make sure you're setting any references to this button to nil when you're releasing and making new views 
     // so that you're not addressing a button that's been released 
     // (assigning the image to the button will cause the button to retain it for you) 
     if (titleLogoImage != nil) 
      titleLogoImage.image = loadingImage; 
    } 
    else 
    { 
     [self performSelectorOnMainThread:@selector(setImageForTitleLogo:) withObject:imgData waitUntilDone:NO]; 
    } 
} 
+0

嘿,謝謝你,你是新來的? – 2010-07-29 08:54:39

+0

優秀的反正:)我認爲這是不是在主線程上執行的圖像設置是這個問題。非常感謝:) – 2010-07-29 09:08:09

+0

我現在又一次流行。很高興幫助。 – Doug 2010-08-01 02:35:56

0

你在做奇怪的事情。

NSURL *url = [[NSURL alloc] init]; 

意味着你創建一個NSURL對象,你自己的。

url = [NSURL URLWithString:logoPath]; 

這意味着你創建另一個 NSURL對象,它會被自動釋放。你剛創建的NSURL只是泄漏。這裏的NSData也一樣。

loadingImage必須由titleLogoImage保留,否則它將在您的NSAutoReleasePool的消耗品中被重新分配。什麼是titleLogoImage並保留image

編輯 ps:什麼也擾亂我,是loadingImage不是限制在函數的範圍。要將事物縮短:

NSURL *url = [NSURL URLWithString:logoPath]; 
NSData *data = [NSData dataWithContentsOfURL:url]; 
titleLogoImage.image = [UIImage imageWithData:data]; 

至少可以節省一些麻煩。

+0

這就是我所擁有的,但是當讀到NSAutoReleasePool的時候,我在某個地方讀過這樣的內容......無論如何,即使用我以前的方法,我遇到同樣的問題。不管怎麼說,還是要謝謝你。 – 2010-07-29 08:53:04

0

發佈的代碼中沒有任何內容會觸發崩潰。根據如何定義titleLogoImage,它可能會受到autorelease的影響。

但是,beyond the problems outlined by mvds,您沒有迫切需要本地化的自動釋放池。它在這裏什麼都不會做,但會給你帶來麻煩。

自動釋放池是危險的,不適合初學者。他們會殺死它們中的任何自動釋放對象。當您快速創建大量內存密集型對象時,通常只會創建自己的池。這似乎並非如此。

儘管給予他們關注,但很少使用自定義池。經過十幾年Apple API的工作,我可以指望我使用自己的自定義池的次數。