【发布时间】:2013-03-09 12:32:58
【问题描述】:
我正在做一个 UITableview 来下载数据 webservice 这个名字非常快,所以我最初用它来填充表格,然后我为图像启动了一个操作队列。
然后是其余数据的单独队列,因为它加载非常慢但会影响图像加载时间,我如何同时执行 2 个。
您能找出导致性能下降的原因并帮我解决吗?
【问题讨论】:
标签: ios objective-c uitableview objective-c-blocks
我正在做一个 UITableview 来下载数据 webservice 这个名字非常快,所以我最初用它来填充表格,然后我为图像启动了一个操作队列。
然后是其余数据的单独队列,因为它加载非常慢但会影响图像加载时间,我如何同时执行 2 个。
您能找出导致性能下降的原因并帮我解决吗?
【问题讨论】:
标签: ios objective-c uitableview objective-c-blocks
我假设您知道,您可以在创建队列时通过设置maxConcurrentOperationCount 来指定并发请求的数量。四是典型值。
self.imageDownloadingQueue.maxConcurrentOperationCount = 4;
问题是,你不能比这更大(由于 iOS 限制和一些服务器限制)。可能有 5 个,但不会比这个大。
就我个人而言,我不会用完有限数量的最大并发操作返回文本值。我会提前检索所有这些。您会延迟加载图像,因为它们太大了,但文本条目太小,以至于执行单独的网络请求的开销开始施加其自身的性能损失。如果您要延迟加载描述,我会分批下载 50 或 100 个左右。
查看您的源代码,您发出的 JSON 请求至少是您应该发出的两倍(您在 getAnimalRank 和 getAnimalType 中检索相同的 JSON)。但是你真的应该改变最初的 JSON 请求来返回你需要的一切,名称、等级、类型、URL(但不是图像本身)。然后在一次调用中,您就可以获得所需的一切(除了我们将异步检索的图像,以及您的服务器为 UX 快速交付的图像)。如果您决定保留对排名/类型/url 的各个请求,则需要查看您的服务器代码,因为没有正当理由不应该立即返回,而且目前确实很慢。但是,正如我所说,您真的应该在初始 JSON 请求中返回所有这些内容,这样您的用户界面将会非常快。
最后一点:您正在使用单独的队列来获取详细信息和图像下载。使用NSOperationQueue 和设置maxConcurrentOperationCount 的全部目的是iOS 只能对给定服务器执行5 个并发请求。通过将它们放在两个单独的队列中,您将失去maxConcurrentOperationCount 的好处。事实证明,请求超时需要一分钟,所以您可能不会遇到问题,但它仍然反映了对队列用途的基本误解。
归根结底,您应该只有一个网络队列(因为系统限制是您的设备与任何给定服务器之间的网络并发连接数,而不是图像下载量,以及单独下载描述的数量)。
【讨论】:
您是否考虑过异步执行此操作?我写了一个类来做一些与你使用块描述的非常相似的事情。您可以通过两种方式做到这一点:
只要 cellForRowAtIndexPath 触发就加载异步。这适用于很多情况,但可能会导致错误的图像显示一秒钟,直到正确的图像完成加载。
在拖动停止时调用进程以加载图像。这通常是我做事的方式,以便正确的图像始终显示它应该显示的位置。在从网络加载图像之前,您可以使用占位符图像。
查看这个 SO 问题了解详情:
【讨论】:
NSOperationQueue 效率更低。
cellForRowAtIndexPath的问题,这通常是两个错误之一的结果:1.未能正确初始化图像之前你发送图像获取对后台队列的更新(从而看到出列单元格的图像;或 2. 在更新图像之前未能仔细检查 cellForRowAtIndexPath。我喜欢您对另一个问题的回答(带有updateCell 警告),我认为cellForRowAtIndexPath 是最好的地方。你的单独课程是优雅的解决方案。干得好。