我有一个大的UIScrollView,我正在放置3-4个相当大(320x1500像素左右)的UIImageView图像拼贴.我将这些UIImageViews添加到我的NIB文件内的滚动视图中.我的控制器上有一个插座,那就是UIScrollView.我正在使用一个属性(非原子,保留),并将其合并.
我的问题是:当我在Memory Monitor中观察到这一点时,我可以看到,当加载了所有这些图像的视图时(正如预期的那样),所使用的内存会相当大.但是当我离开视图时,它和它的控制器都是dealloc'd,但似乎并没有放弃它们占用的内存附近的任何地方.当我将其中一个视图(我的应用程序中有几个)切割成只有1-3个320x460的图像并将其他所有内容保持相同时,它会重新捕获内存.
使用这么大的图像有什么问题吗?我在这段代码中做错了什么(粘贴在下面)?
这是viewController的一个导致问题的片段.
- (CGFloat)findHeight { UIImageView *imageView = nil; NSArray *subviews = [self.scrollView subviews]; CGFloat maxYLoc = 0; for (imageView in subviews) { if ([imageView isKindOfClass:[UIImageView class]]) { CGRect frame = imageView.frame; if ((frame.origin.y + frame.size.height) > maxYLoc) { maxYLoc = frame.origin.y; maxYLoc += frame.size.height; } } } return maxYLoc; } - (void)viewDidLoad { [super viewDidLoad]; [self.scrollView setContentSize:CGSizeMake(320, [self findHeight])]; [self.scrollView setCanCancelContentTouches:NO]; self.scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite; self.scrollView.clipsToBounds = YES; self.scrollView.scrollEnabled = YES; self.scrollView.pagingEnabled = NO; } - (void)dealloc { NSLog(@"DAY Controller Dealloc'd"); self.scrollView = nil; [super dealloc]; }
更新:我注意到另一个奇怪的现象.如果我不使用视图上的滚动,它似乎挂在内存上.但是如果我滚动一堆并确保所有UIImageViews在某一点上变得可见,它将释放并重新获得它丢失的大部分内存.
UPDATE2:我问这个的原因是我的应用实际上由于内存不足而崩溃.我不介意它只是缓存和耗尽额外的内存,但它似乎永远不会释放它 - 即使在didReceiveMmoryWarning条件下
我已经解开了这个谜 - 我很确定这是苹果方面的一个错误.
正如Kendall所建议的那样(谢谢!),问题在于InterfaceBuilder如何从NIB文件加载图像.当您使用initFromNib时,所有UIImageViews都将使用UIImage的imageNamed:方法使用UIImage进行初始化.此调用使用缓存来处理图像.通常,这是你想要的.但是,对于非常大的图像以及远离可见区域滚动的图像,它似乎不遵守内存警告并转储此缓存.这就是我认为是苹果方面的一个错误(如果你同意/不同意,请发表评论 - 如果其他人同意,我想提交这个).如上所述,如果用户滚动到足以使其全部可见,这些图像使用的内存似乎确实会被释放.
我找到的解决方法(也是肯德尔的建议)是将图像名称留空在NIB文件中.因此,您可以正常布局UIImageView元素,但不要选择图像.然后在viewDidLoad代码中,使用imageWithContentsOfFile进入并加载图像:相反.此方法不会缓存图像,因此不会因保留大图像而导致任何内存问题.
当然,imageNamed:更容易使用,因为它默认为bundle中的任何东西,而不是必须找到路径.但是,您可以使用以下命令获取包的路径:
NSString *fullpath = [[[NSBundle mainBundle] bundlePath];
把它们放在一起,这就是代码中的样子:
NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:[NSString stringWithFormat:@"/%@-%d.png", self.nibName, imageView.tag]]; UIImage *loadImage = [UIImage imageWithContentsOfFile:fullpath]; imageView.image = loadImage;
所以将它添加到我上面的代码中,完整的函数如下所示:
- (CGFloat)findHeight { UIImageView *imageView = nil; NSArray *subviews = [self.scrollView subviews]; CGFloat maxYLoc = 0; for (imageView in subviews) { if ([imageView isKindOfClass:[UIImageView class]]) { CGRect frame = imageView.frame; if ((frame.origin.y + frame.size.height) > maxYLoc) { maxYLoc = frame.origin.y; maxYLoc += frame.size.height; } NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:[NSString stringWithFormat:@"/%@-%d.png", self.nibName, imageView.tag]]; NSLog(fullpath); UIImage *loadImage = [UIImage imageWithContentsOfFile:fullpath]; imageView.image = loadImage; } } return maxYLoc; }