简体   繁体   English

是否可以仅使用NSURLSession为UITableViews构建异步图像下载机制? 怎么样?

[英]Is it possible to build an asynchronous image downloading mechanism for UITableViews with just NSURLSession? How?

I want to build an image downloader for my UITableView so images can be loaded asynchronously into the table view. 我想为我的UITableView构建一个图像下载器,这样可以将图像异步加载到表视图中。

With NSURLSession automatically using NSURLCache to cache HTTP requests, will I be able to depend on that solely as my caching mechanism? 使用NSURLSession自动使用NSURLCache来缓存HTTP请求,我是否能够仅依赖于我的缓存机制? I notice many use NSCache to save the downloaded image, but if NSURLSession already implements a cache, is that necessary? 我注意到很多人使用NSCache来保存下载的图像,但是如果NSURLSession已经实现了缓存,那还有必要吗? If anything, isn't it bad, as I'm duplicating a copy of the image in memory? 如果有的话,是不是很糟糕,因为我在内存中复制了一份图像副本?

Furthermore, if it's possible, how do I use this in conjunction with UITableView ? 此外,如果可能,我如何将其与UITableView结合使用? Cell reuse presents an interesting issue with assigning the result of a background transfer. 细胞重用在分配背景转移的结果时提出了一个有趣的问题。

I can't simply download the image using NSURLSessionDownloadTask and in the completion block set the cell's image, as by the time it downloads the cell may have been reused and thus causing it to set it to the wrong cell. 我不能简单地使用NSURLSessionDownloadTask下载图像,并在完成块中设置单元格的图像,因为下载单元格时可能已经重复使用,从而导致它将其设置为错误的单元格。

let downloadTask = session.downloadTaskWithURL(URL, completionHandler: { location, response, error in
    var dataFetchingError: NSError? = nil
    let downloadedImage = UIImage(data: NSData.dataWithContentsOfURL(location, options: nil, error: &dataFetchingError))

    dispatch_async(dispatch_get_main_queue()) {
        // Might end up on the wrong cell
        cell.thumbnail.image = downloadedImage
    }
})

So how do I make sure that the assigned image makes its way to the correct cell, and that I'm caching these downloads properly? 那么如何确保分配的图像进入正确的单元格,并且我正确地缓存这些下载?

I'm aware of SDWebImage and the like, but I'd like to try to solve this problem without the use of a library. 我知道SDWebImage等,但我想尝试在不使用库的情况下解决这个问题。

You can just have the final dispatch to the main queue see if the cell was still visible before updating the image cell. 在更新图像单元格之前,您可以对主队列进行最终调度,以查看单元格是否仍然可见。 You can do this using cellForRowAtIndexPath (not to be confused with the similarly named UITableViewDataSource method): 您可以使用cellForRowAtIndexPath执行此操作(不要与类似名称的UITableViewDataSource方法混淆):

dispatch_async(dispatch_get_main_queue()) {
    if let updateCell = tableView.cellForRowAtIndexPath(indexPath) as? MyCell {
        updateCell.thumbnail.image = downloadedImage
    }
}

(Note, this assumes that the index path of the cell cannot possibly change while the asynchronous update is in progress. If it's possible that you can insert/delete rows while the update is in progress, you should not just use the old indexPath , but rather go back to the model and recalculate the appropriate index path for this cell.) (注意,这假设在异步更新正在进行时,单元的索引路径不可能更改。如果在更新过程中可能插入/删除行,则不应该只使用旧的indexPath ,而是而是回到模型并重新计算此单元格的相应索引路径。)

Obviously, those UIImageView categories offer other advantages besides just updating the image view asynchronously. 显然,除了仅异步更新图像视图外,这些UIImageView类别还提供其他优势。 For example, if the cell is reused, these categories will cancel any old pending network requests for that cell. 例如,如果重用该单元,则这些类别将取消该单元的任何旧的待处理网络请求。 This is important so that if you scroll quickly, the currently visible cells will otherwise get backlogged behind download requests for cells that may have long since scrolled out of view. 这一点很重要,因此如果您快速滚动,当前可见的单元格将会在可能早已滚出视图的单元格的下载请求后面积压。

But if you're only concerned about the making sure that a cell is still visible before updating the image, the above should address that. 但是,如果您只关心在更新图像之前确保单元格仍然可见,则上述内容应该解决这个问题。


Regarding your cache question, there are two different types of cache to discuss: RAM cache and persistent storage cache. 关于缓存问题,有两种不同类型的缓存可供讨论:RAM缓存和持久存储缓存。 Both SDWebImage and AFNetworking UIImageView categories implemented their own RAM cache (using NSCache ) for performance. SDWebImage和AFNetworking UIImageView类别都实现了自己的RAM缓存(使用NSCache )以提高性能。 For persistent storage caching, though, SDWebImage implemented their own, and AFNetworking argued that one should rely on the built-in NSURLCache for that. 但是,对于持久性存储缓存,SDWebImage实现了自己的缓存,AFNetworking认为应该依赖内置的NSURLCache I'm sympathetic to the SDWebImage perspective because (a) historically NSURLConnection caching to persistent storage on iOS was inconsistent; 我同情SDWebImage透视图,因为(a)历史上NSURLConnection缓存到iOS上的持久存储是不一致的; (b) caching can easily be disturbed by the server using the wrong headers in the responses; (b)服务器在响应中使用错误的标题很容易干扰缓存; and (c) Apple has been annoying opaque on the criteria for when something gets cached and when it doesn't. (c)Apple在缓存某些东西和不缓存某些东西时的标准上一直很不透明。

So bottom line, there's probably a good argument to implement a NSCache mechanism if you want silky-smooth scrolling, but you might be able to get away with relying on NSURLCache for persistent storage caching. 如此底线,如果你想要丝滑平滑的滚动,实现NSCache机制可能是一个很好的论据,但是你可以依靠NSURLCache来实现持久存储缓存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM