当前位置:  开发笔记 > 编程语言 > 正文

问题是在UIScrollView中使用相当大的图像来释放UIImageViews所使用的内存

如何解决《问题是在UIScrollView中使用相当大的图像来释放UIImageViews所使用的内存》经验,为你挑选了1个好方法。

我有一个大的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条件下



1> Bdebeez..:

我已经解开了这个谜 - 我很确定这是苹果方面的一个错误.

正如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;
}

推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有