2010-07-28 78 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的工作,我可以指望我使用自己的自定义池的次数。