为什么我的addSubview:方法导致泄漏?

时间:2011-02-06 02:43:26

标签: iphone memory memory-management memory-leaks

好的,所以我已经对此做了大量的研究,并且已经把我的头发拉了几天试图找出以下代码泄漏的原因:

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
UIImage *comicImage = [self getCachedImage:[NSString stringWithFormat:@"%@%@%@",@"http://url/",comicNumber,@".png"]];
self.imageView = [[[UIImageView alloc] initWithImage:comicImage] autorelease];
[self.scrollView addSubview:self.imageView];
self.scrollView.contentSize = self.imageView.frame.size;
self.imageWidth = [NSString stringWithFormat:@"%f",imageView.frame.size.width];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

self.imageView和self.scrollView都是@propety(非原子,保留)并在我的dealloc中发布..在代码中的其他任何地方都不使用imageView。此代码也在主线程的线程中运行。如果我在我的设备上运行此代码,如果我不断加载此视图,它将很快耗尽内存。但是,我发现如果我注释掉以下行:

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
UIImage *comicImage = [self getCachedImage:[NSString stringWithFormat:@"%@%@%@",@"http://url/",comicNumber,@".png"]];
self.imageView = [[[UIImageView alloc] initWithImage:comicImage] autorelease];
//[self.scrollView addSubview:self.imageView];
self.scrollView.contentSize = self.imageView.frame.size;
self.imageWidth = [NSString stringWithFormat:@"%f",imageView.frame.size.width];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

无论加载视图多少次,内存使用都会变得稳定。我已经完成了我能想到的一切,看看为什么会泄漏,但据我所知,我的所有发布都是直接的。谁能看到我失踪的东西?

3 个答案:

答案 0 :(得分:1)

您在初始化时自动释放您的imageview,然后通过将其分配给self.imageView来保留它,然后将其添加为子视图再次保留它。因此,当池耗尽时,它会收到一条释放消息。当它作为子视图被删除时,它会获得一条释放消息。然后,如果你dealloc,它会获得第三个发布消息。其中一个没有发生。你说它是以dealloc发布的,所以不是这样。可以信任自动释放池在某个时刻消耗掉,所以不是这样。我要么确保在某个时候将其作为子视图删除,要么删除一个保留调用。

并且......不应该这样:

self.imageView = [[[UIImageView initWithImage:comicImage] autorelease];
是吗?:

self.imageView = [[UIImageView alloc] initWithImage:comicImage];

答案 1 :(得分:0)

调用此行时:

[self.scrollView addSubview:self.imageView];

self.imageView由其超级视图保留,当您不再需要imageView时,您应该调用:

[self.imageView removeFromSuperview];

这将在self.imageView上调用release。

P.S。您可以通过调用

来跟踪您的参考计数
NSLog(@"RefCount: %d", [self.imageView retainCount]);

上面添加此行
self.imageView = [[[UIImageView initWithImage:comicImage] autorelease];

跟踪refCount。 (更好的选择是使用乐器,但你已经知道:))

编辑:当你保留这样的属性时,[[alloc] init]对象是一个好习惯:

UIView *myView = [[UIView alloc] init];
self.myCustomView = myView;
[myView release];

否则你将获得self.myCustomView保留两次。

答案 2 :(得分:0)

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

精细。

UIImage *comicImage = [self getCachedImage:[NSString stringWithFormat:@"%@%@%@",@"http://url/",comicNumber,@".png"]];

除非你遵循标准的Cocoa模式(这种方法不是这样),否则不要调用方法get*。只需将其称为cachedImage:

self.imageView = [[[UIImageView initWithImage:comicImage] autorelease];

您错过了alloc电话;应该是:

self.imageView = [[[UIImageView alloc] initWithImage:comicImage] autorelease];

或者(如果你想避免自动释放池;可能不是这里的问题):

UIImageView *iV = [[UIImageView alloc] initWithImage:comicImage];
self.imageView = iV;
[iV release];

[self.scrollView addSubview:self.imageView];
self.scrollView.contentSize = self.imageView.frame.size;
self.imageWidth = [NSString stringWithFormat:@"%f",imageView.frame.size.width];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

一切都很好。如果有泄漏,可能是因为imageView没有在dealloc中释放,或者其他东西挂在它上面(scrollView没有被释放,偶然?)。仪器可以很好地追踪泄漏等......


“泄漏”工具寻找的是不再有任何引用的对象。在这种情况下,你很可能还有引用。

坦率地说,鉴于您很容易通过重复来重现增长,因此快照分析很可能非常适用。

我之前写了guide on Heapshot analysis