我有一个小型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弹出。我确信这是由于线程池中的代码,但任何人都可以看到为什么会发生这种情况?
由于
答案 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工作,我可以指望我使用自己的自定义池的次数。