iPhone上的NSAutoreleasePool问题

时间:2010-07-28 22:45:05

标签: iphone nsthread nsautoreleasepool

我有一个小型iPhone应用程序,第一个视图上有一个按钮。当我选择这个按钮时,我加载了我的新视图,上面有一个图像。我目前正在使用以下代码在单独的线程上从在线源加载图像,同时允许用户继续控制应用程序:

- (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弹出。我确信这是由于线程池中的代码,但任何人都可以看到为什么会发生这种情况?

由于

3 个答案:

答案 0 :(得分: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];
    }
}

答案 1 :(得分: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];

至少可以省去一些麻烦。

答案 2 :(得分:0)

发布的代码中没有任何内容会触发崩溃。根据titleLogoImage的定义方式,它可能会受到自动释放的影响。

但是,beyond the problems outlined by mvds,您对本地化自动释放池没有迫切需求。它在这里什么也不做,但会给你带来麻烦。

自动释放池很危险,不适合初学者。他们将杀死其中的任何自动释放的对象。通常,只有在快速创建大量内存密集型对象时才创建自​​己的池。这似乎不是这种情况。

尽管给予了关注,但很少使用自定义池。经过十多年的Apple API工作,我可以指望我使用自己的自定义池的次数。