NS操作加载图像到单元格 - 崩溃

问题描述:

即时通讯使用NSOperation下载每个单元格的图像,所以我不会超载用户沉重的图像加载。这工作99%的时间,但不时我得到一个零我的操作块和应用程序崩溃。NS操作加载图像到单元格 - 崩溃

这是代码:

cell.blockImage.image = nil 
    cell.queue.cancelAllOperations() 

    let cacheKey = indexPath.row 

    if(self.imagesDictionary.object(forKey: cacheKey) != nil) 
    { 
     cell.blockImage.image = self.imagesDictionary.object(forKey: cacheKey) as? UIImage 
    } 
    else 
    { 
     let operation: BlockOperation = BlockOperation() 
     operation.addExecutionBlock({ 

      if let url = NSURL(string: self.arrJSONData[indexPath.row].image) { 
       if let data = NSData(contentsOf: url as URL) { 
        if let image: UIImage = UIImage(data: data as Data) 
        { 
         self.imagesDictionary.setObject(image, forKey: cacheKey as NSCopying) 
         DispatchQueue.main.async(execute: { 

          if(operation.isCancelled) 
          { 
           return 
          } 

          cell.blockImage.image = image 
         }) 
        } 
       } 
      } 



     }) 

     cell.queue.addOperation(operation) 

    } 

所以我去下载图像,并将其存储在一个字典中。关键是单元格的indexPath.row。

我也验证图像是否已经在字典中,所以我不再下载它。

而我总是将我的图像设置为零,并在我开始加载单元格时取消BlockOperation。

错误我总是得到的是:

malloc: *** error for object 0x608000244c50: Invalid pointer dequeued from free list 
*** set a breakpoint in malloc_error_break to debug 

,我总是得到它该块内(但线始终是随机的)

if let image: UIImage = UIImage(data: data as Data) 
{ 
    self.imagesDictionary.setObject(image, forKey: cacheKey as NSCopying) 
    DispatchQueue.main.async(execute: { 

     if(operation.isCancelled) 
     { 
      return 
     } 

     cell.blockImage.image = image 
    }) 
} 

我到底做错了什么?谢谢。

+1

我不知道为什么你崩溃,但你应该考虑使用类似https://github.com/Alamofire/AlamofireImage – EricD

+0

林外部库不是一个球迷,但我应该研究一下这个库正在做什么。谢谢! – Gusfat

几个问题:

  1. 如果使用NSMutableDictionary,必须同步与字典中的所有互动。 NSMutableDictionary不是线程安全的。如果您使用NSCache,它具有非常类似的接口,它提供了线程安全的交互,因此不需要手动同步。

  2. 此外,你不应该只是更新cell里面的操作。您不知道与该索引路径关联的单元格是否仍然可见(或更糟糕的是,它是否已被重新用于其他索引路径)。您应该使用cellForRow(at:)(不要与名称相似的UITableViewDataSource方法混淆)以获取与该IndexPath关联的当前单元格。如果返回非nil单元格引用,您是否应该使用它来更新单元格的图像。如果它是nil,则不会更新可见的UIImageView

  3. 与您的崩溃无关,如果快速滚动浏览表格视图,您的网络请求队列可能会得到积压,下载不再可见的单元格图像。例如,如果快速滚动到第100行,对可见单元格的请求可能会滞后于对不再可见的前99行的请求。如果他们有低速网络连接(您应该尝试使用“网络链路调节器”进行模拟),这个问题将会被放大。

    什么让这更成问题是您正在使用同步,不可取消的网络请求。如果您像EricD所建议的那样使用UIImageView扩展中的一个来扩展异步图像检索(例如AlamofireImageKingfisher等;这里有很多),则可以减轻此问题。

+0

对不起等了很久,我今天只有时间看看这个问题。那么我最终使用了翠鸟,它为我节省了很多麻烦。谢谢,罗伯! – Gusfat