【问题标题】:Memory growing in UITableViewCellUITableViewCell 中的内存增长
【发布时间】:2015-10-22 17:46:43
【问题描述】:

我的自定义单元格代码:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ImageView"];
    NSURL *nsurl = [NSURL URLWithString:_imageUrls[indexPath.row]];
    NSData *data = [NSData dataWithContentsOfURL: nsurl];

    cell.imageView.image = [UIImage imageWithData:data];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ImageView"];
    }

    return cell;

我有自定义类 VKTableViewCell:

   @interface VKTableViewCell : UITableViewCell
    @property (weak, nonatomic) IBOutlet UIImageView *image;

    @end

图片约为 800x800(从网站解析)。 当我滚动我的表格时,内存在增长(从 20 到 30mb,加载 100 张图像)。为什么会这样?在这种情况下我必须做什么?我正在使用 ARC。

【问题讨论】:

  • 虽然与此问题无关,但您可能应该在创建新单元格的调用之后调用设置图像。 (在 dequeReusableCellWithIdentifier 返回 nil 的情况下。
  • 你所做的一切都是错误的。您不得cellForRow 中同步使用网络。您必须立即返回单元格。用户正在现在滚动。 现在返回一个单元格。
  • @matt 我还知道服务质量和线程。这不是最后一个版本的代码。但是假设是主线程,内存泄漏正常吗?
  • 每次我们看到相同的单元格时,您都在下载图像(例如,上下滚动和上下滚动)。那是疯癫。 将图像存储在数据模型中。你所做的一切都是错误的。 (我想我是这么说的。)
  • @matt 谢谢,我会做的

标签: ios uitableview custom-cell


【解决方案1】:

您正在主线程上进行网络调用,这就是它同时做两件事的原因

  1. 渲染 UITableView 单元格

  2. 对图像进行网络调用

现在您必须将网络调用逻辑从 Main Thread to BackGround Thread 转移

dispatch_queue_t callerQueue = dispatch_get_current_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("com.myapp.processsmagequeue", NULL);
dispatch_async(downloadQueue, ^{
    NSData * imageData = [NSData dataWithContentsOfURL:url]; //Make Network call on BackGround Thread

    dispatch_async(callerQueue, ^{
        // Assign Your Image to UIimageView of Cell here on Main Thread
        [cell setNeedsLayout]; // To Refresh Cell
    });
});

您也可以使用第三方 API AFNetWorkingSDWebImage

[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];

新解决方案:

延迟加载 UITableViewCell 中的所有图像,只需制作如下所示的 UIImageView 扩展

extension UIImageView {
    func downloadImageFrom(_ link:String, contentMode: UIView.ContentMode) {

        guard let url = URL(string: link) else {
           return
        }
        URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
            guard let `self` = self else { return }
            DispatchQueue.main.async {
                self.contentMode = contentMode
                self.image = UIImage(data: data ?? Data())
            }
        }.resume()
    }
}

函数调用:

cell.imageView.image = UIImage(named: "placeholder")  //set placeholder image first.
cell.imageView.downloadImageFrom(link: dataSource[indexPath.row], contentMode: UIViewContentMode.ScaleAspectFit)  //set your image from link array.

【讨论】:

  • 我使用了你的方法。但是如何在不重新加载单元格的情况下刷新?当它被加载时它是空的。
  • 一旦您将获得 imageData 然后在下一步中,您必须将该数据分配给主线程上的 cell.imageView。通过这样做,您不必再次重新加载单元格
  • dispatch_async(callerQueue, ^{ cell.imageView.image = [UIImage imageWithData:imageData]; })。之后,只有当我单击单元格时才会出现图像。默认为空,但已加载图片。
  • 那么这里有 2 个选项 1- 在此行上放置一个断点,将数据分配给 uiimageView,第二个是检查单元格的背景颜色并下载图像
  • 我认为图片是从网络下载的,但分配时出现了一些问题
猜你喜欢
  • 2013-01-02
  • 2018-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
  • 2014-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多