我遇到了一个问题。我的应用程序从服务器下载图像并显示在 UITableView
中 为了下载图像,我使用 dispatch_async
。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// downloading image from server
dispatch_async(dispatch_get_main_queue(), ^{
// update UI for showing downloaded image
});
});
现在的问题是,如果用户上下滚动速度非常快,那么多个 dispatch_async
会为同一张图片触发。我有图像 ID。有什么方法可以通过图像 ID 检查 dispatch_async
是否为该图像被触发?
最佳答案
您必须设置自己的机制来跟踪是否有任何对该图像的未决请求(例如,由图像 URL 绝对字符串或类似内容键入的字典)。问题是,事情并没有那么简单,因为现在需要更新的单元格可能不同于(或除了)最初请求它的单元格。这很快就会变得丑陋。
但我会退后一步,问问这是根本问题还是更广泛问题的症状。例如,如果用户相对快速地向下滚动到第 100 行。该图像请求是否积压在前 99 行之后?当你处于那种情况时,你描述的问题开始变得严重,因为如果你现在在其他 99 张图像完成下载之前快速滚动回到顶部,你将发出获取它们的请求 再次。
但是,如果您更改异步图像检索以取消对不可见单元格的请求,那么这个严重的问题突然变得有点学术化了。此外,您还有一个额外的好处,即用户快速滚动到的第 100 行的图像不会积压在所有其他图像请求之后,因此它显示得非常快。
这意味着您要使用可取消的异步请求。因此,这将建议使用 NSURLSession
(如果您必须支持早于 NSURLSession
的操作系统版本,则使用基于委托(delegate)的 NSURLConnection
)。此外,这通常会使人倾向于操作队列和子类异步 NSOperation
子类,而不是您的问题建议的 GCD 队列(使它们可取消、异步,并限制并发程度)。然后,您必须实现使用您辛勤创建的所有取消逻辑的代码(例如 UIImageView
类别或您的 UITableViewDataSource
和/或 UITableViewCell
子类使用)。
另外,您要确保使用缓存机制(可能同时用于内存和持久存储)。这样,如果您已经检索到特定图像,当您滚动回该行时,该图像已准备好供您检索,无需再次调用网络。
我知道您曾说过您想自己做这件事,但要正确完成这项工作并非易事。这就是为什么我(和其他人)建议您考虑检查允许您异步检索图像的 UIImageView
类别之一。查看 SDWebImage 提供的 UIImageView
类别或 AFNetworking .如果您正确地使单元格出列,这些单元格将在异步检索图像的同时实现非常灵敏的 UI。他们有效地取消了对重复使用的单元格的请求,从而优先考虑可见单元格。它们还会缓存结果,从而在您向后滚动时获得良好的性能。
关于ios - 如何检查dispatch_async是否被提前调用以进行相同的操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29132095/