UICollectionView 在滚动时收到内存警告

Posted

技术标签:

【中文标题】UICollectionView 在滚动时收到内存警告【英文标题】:UICollectionView received memory warning while scrolling 【发布时间】:2014-03-31 21:08:17 【问题描述】:

我正在开发一个带有UICollectionViewViewController 的应用程序。

这个CollectionView 是一个画廊,每行有 3 张图片。

我以 30 张图片为一组从服务器获取图像,第一个 url 和代码,当单元格将显示在 cellForItemAtIndexPath 时,我使用 SDWebImage Library 异步下载这些图片。每 30 张图片我再次调用 Web 服务,我会收到 30 张图片,发送带有限制和偏移的请求。这可能发生 100 次,有 3000 张图片的配置文件。

好吧,我的问题来了,我在 iPhone 4 中启动了该应用程序,经过快速滚动后,我开始收到 Received Memory Warnings,并在收到一些警告后应用程序崩溃了。当我在模拟器中进行相同的测试时,没有任何不好的事情发生。

每次下载 30 张图片时,我都会将结果数组添加到处理 CollectionView 数据的 NSMutableArray *data propertyreload collectionView。我曾尝试将 Instruments 与分配一起使用,但我很难理解发生了什么。

这是我用来创建单元格的代码

-(UICollectionViewCell *)collectionView:(LZProfileImagesCollectionView *)aCollectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
    if(aCollectionView == self.imagesCollectionView)
        if([self.data count] - 12 == indexPath.row)
            self.photoOffset += 30;
            [self loadUserData];
        

        LZProfileCollectionViewCell * cell = (LZProfileCollectionViewCell *)[imagesCollectionView dequeueReusableCellWithReuseIdentifier:ImageCollectionCellIdentifier forIndexPath:indexPath];
        Image *image =(self.data)[indexPath.row];
        [cell configureCellWithImage:image];

        return cell;
    
    return  nil;

LZProfileCollectionViewCell 单元格中,我有这个:

-(void)configureCellWithImage:(Image *)image

    [self setNeedsDisplay];

    // Imagen
    NSString *imageUrl  = [kBaseURL stringByAppendingString:image.imageStringUrl];
    [self.pictureImg setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:kDefaultLoadingImage]];
    [self.pictureImg setContentMode:UIViewContentModeScaleAspectFit];


我已从SDWebImage 取走setImageWithURL

3 分钟后,我在 Instruments(Statistics) 中获得了这张快照

提前谢谢你

【问题讨论】:

如果您使用的是第三方库,您需要确保已对其进行配置以进行适当的缓存。当您需要释放内存时,您还负责清除该缓存。分配工具对内存的使用位置有何看法? 我使用AFNetworking 处理普通请求,SDWebImage 用于图像异步下载。您希望在工具分配中看到什么?调用树,分配列表? Statistics->Object Summary 开始,然后查看顶部的Live Bytes 对象。或发布屏幕截图。也拍一些照片。 【参考方案1】:

好吧,您将每个图像都缓存在一个数组中,因此一旦缓存了如此多的图像,您最终会耗尽内存。它不会在模拟器上发生,因为模拟器的内存与运行它的计算机一样多,所以它不太可能耗尽内存,但是真正的设备会很快耗尽。我会自己处理内存错误并清空数组,为新图像腾出新空间。或者更好的是创建自己的缓存机制来保存和清除一段时间未显示的图像,无论哪种方式,您都必须在达到某个阈值后通过某种方式转储图像。

【讨论】:

但是..我的数组只保存图片的URL和代码,不保存图片本身 这不是正确的答案,问题是你永远不会释放每个单元格中加载的图像【参考方案2】:

– didReceiveMemoryWarning 方法中,您应该释放存储图像的数组的一些内存。也许您未显示的第一张图像将其存储在第二个数组中,例如辅助数组。

【讨论】:

但是,如果我再次向上滚动,我应该再次替换数组中的项目,不是吗?【参考方案3】:

这可能是因为很多UIImage 对象最终都在内存中。您可以改为将其缓存在磁盘上。 AFNetworking 有一个很好的 UIImageView category 可以自动完成所有这些操作。

如果您没有将图像保存在 dataSource 数组中,那么它们可能会保留在其他地方,这是一个错误。

另外,请确保您是 dequeuing 单元格而不是创建新单元格。

【讨论】:

我使用setImageWithURL SDWebImage 库方法。是不是很像? 它们的最终效果可能差不多,但我不确定SDWebImage是否做磁盘缓存。 SDWebImage 具有自动缓存过期处理的异步内存+磁盘映像缓存 github.com/rs/SDWebImage 我实际上不这样做。我只是将图像保存在缓存中,而不是磁盘缓存。我去试试 如何使用 AFNetworking 将我的图像缓存在磁盘上?我不认为 AFNetworking 会自动执行此操作。我已经尝试过使用该类别的[self.pictureImg setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:kDefaultLoadingImage]];,并且发生了同样的情况。我也不能用 SDWebImage 做到这一点。我已经意识到问题不在于我滚动时,而在于单元格将图像放入缓存中,如你所说。【参考方案4】:

我遇到过类似的情况,所以我在回复这个问题,虽然原因似乎与你的有点不同。

我在 UITableViewCell 中有一个水平的 UICollectionView。当我快速左右滚动 UICollectionView 时,整个 UI(甚至是主页按钮)都会停止,一段时间后应用程序崩溃并在控制台上显示消息“来自调试器的消息:由于内存问题而终止”即使没有 didReceiveMemoryWarning 调用。

我使用 UICollectionViewCell 对其进行了测试,没有任何 UI 组件但没有任何更改。 XCode Profile 工具说它实际上在 UI 停止期间一直分配内存,直到它崩溃,即使其中没​​有任何 UI 组件。

唯一可疑的一点是,我用 AppDelegate.window.size.width * 0.35 设置 UICollectionViewCell 的子视图的宽度(自定义 UIView 固定到所有超级视图边缘)以确定 UICollectionViewCell 的宽度和它是一个浮点值,例如 130.25

当我将此值硬编码为 130 时,所有崩溃都消失了。我认为在 130.25 这个模糊值的情况下发生了一些事情,它偶尔将宽度确定为 130 或 130.25。

所以我现在使用 CGFloat(Int(AppDelegate.window.size.width * 0.35)) 一切都很好。

【讨论】:

以上是关于UICollectionView 在滚动时收到内存警告的主要内容,如果未能解决你的问题,请参考以下文章

来自调试器的消息:在 UITableView/UICollectionView 中使用 gif 图像 Kingfisher 库滚动时因内存问题而终止

收到内存警告时 UICollectionView 维护的单元队列会发生啥?

滚动 UICollectionView 使用大量内存导致崩溃

使用 UICollectionView 和 MPMediaItemArtwork 遇到内存泄漏

使用 UICollectionView 收到内存警告以查看图像

Base64 图像的 UICollectionView / TableView 内存分配问题