iOS-下载多个图像时超时异常
首先,让我解释一下我是做什么的。我需要用图像在iOS-下载多个图像时超时异常,ios,swift,asynchronous,grand-central-dispatch,Ios,Swift,Asynchronous,Grand Central Dispatch,首先,让我解释一下我是做什么的。我需要用图像在MKMapView上绘制大约一百个注释。我的客户机提供了一个SDK,它提供了近100个对象,我应该在地图上显示这些对象 这就是我从SDK中获取项目的方式 SDKRequest.Request(request) { (items, error) -> Void in dispatch_async(dispatch_get_main_queue(), { // Update UI
MKMapView
上绘制大约一百个注释。我的客户机提供了一个SDK,它提供了近100个对象,我应该在地图上显示这些对象
这就是我从SDK中获取项目的方式
SDKRequest.Request(request) { (items, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
// Update UI
})
}.execute()
}
每个项目都有标题、id、图像等属性。要获取图像,SDK有一个API
item!.loadImage(/*desired size*/) { (image, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
// Update UI
})
}
我得到了将近100个项目,为了下载与该项目相关联的图像,我运行了一个for循环。当一次发送所有100个下载图像的请求时,在下载大约30-40个图像后,我得到请求超时异常
成功下载图像后,我将图像设置为相应的注释,并将其添加到地图中。最后,我最终只在地图上添加了30-40个项目(共100个)
为了解决这个问题,我可以把它作为一个递归函数,这不是一个真正的想法
因此,要处理这种情况,我如何调节这种多次下载,这是最好的方法?下载100幅图像并存储它不是一个好主意。您也可以通过缓存来实现。在图像下载之前,您可以显示缩略图图像。您可以通过
AFNetworking+UIImageView
category轻松实现它,并且还有其他类可用于此目的。如果已经请求了图像url并且缓存了它,那么它将不会再次下载,并为您提供更好的性能。下载100个图像并存储它不是一个好主意。您也可以通过缓存来实现。在图像下载之前,您可以显示缩略图图像。您可以通过AFNetworking+UIImageView
category轻松实现它,并且还有其他类可用于此目的。如果已经请求了图像url,并且缓存了该url,那么它将不会再次下载,并为您提供更好的性能。在没有某种节流机制的情况下,为每个图像发送请求不是最好的实现。这可能是您超时异常的原因
调度信号灯在批量情况下工作得很好。只有当调用线程需要被阻塞时,分派信号才向下调用内核。如果调用信号不需要阻塞,则不进行内核调用
苹果开发者库-
之后,计算剩余的操作,并在它们完成时实现一个完成处理程序。或集团运营等
dispatch_async(serialQueue) {
dispatch_async(main_queue()) {...stuff...}
}
第二个选项使用NSOperation
和NSOperationQueue
如果您想尝试以下建议的NSOperation
和NSOperationQueue
有一个很好的教程
NSOperation
和NSOperationQueue
构建在GCD之上<代码>NSOperation与GCD相比增加了一点额外的开销,但您可以在各种操作之间添加依赖项,并重新使用、取消或挂起它们
正如RW页面所示,代码看起来是这样的。用例是不同的,但这是没有递归的一般想法
斯威夫特行动
class PendingOperations {
lazy var downloadsInProgress = [NSIndexPath:NSOperation]()
lazy var downloadQueue:NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Download queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
}
实现该方法
func startDownloadForMap(...params...){
if let downloadOperation = pendingOperations.downloadsInProgress... {
return
}
let downloader = ImageDownloader(...)
downloader.completionBlock = {
if downloader.cancelled {
return
}
dispatch_async(dispatch_get_main_queue(), {
self.pendingOperations.downloadsInProgress.(do_your_thang)
// ...code
})
}
pendingOperations.downloadsInProgress... = downloader
pendingOperations.downloadQueue.addOperation(downloader)
}
在没有某种节流机制的情况下,对每个图像发送请求并不是最好的实现。这可能是您超时异常的原因 调度信号灯在批量情况下工作得很好。只有当调用线程需要被阻塞时,分派信号才向下调用内核。如果调用信号不需要阻塞,则不进行内核调用 苹果开发者库- 之后,计算剩余的操作,并在它们完成时实现一个完成处理程序。或集团运营等
dispatch_async(serialQueue) {
dispatch_async(main_queue()) {...stuff...}
}
第二个选项使用NSOperation
和NSOperationQueue
如果您想尝试以下建议的NSOperation
和NSOperationQueue
有一个很好的教程
NSOperation
和NSOperationQueue
构建在GCD之上<代码>NSOperation与GCD相比增加了一点额外的开销,但您可以在各种操作之间添加依赖项,并重新使用、取消或挂起它们
正如RW页面所示,代码看起来是这样的。用例是不同的,但这是没有递归的一般想法
斯威夫特行动
class PendingOperations {
lazy var downloadsInProgress = [NSIndexPath:NSOperation]()
lazy var downloadQueue:NSOperationQueue = {
var queue = NSOperationQueue()
queue.name = "Download queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
}
实现该方法
func startDownloadForMap(...params...){
if let downloadOperation = pendingOperations.downloadsInProgress... {
return
}
let downloader = ImageDownloader(...)
downloader.completionBlock = {
if downloader.cancelled {
return
}
dispatch_async(dispatch_get_main_queue(), {
self.pendingOperations.downloadsInProgress.(do_your_thang)
// ...code
})
}
pendingOperations.downloadsInProgress... = downloader
pendingOperations.downloadQueue.addOperation(downloader)
}
上面描述的逻辑基本上是正确的,除了一个小错误,即调度信号量等待(信号量,调度时间永远)应该移动到“for”循环中,就在downloader的上面。downloadAsync(图像,…)但是,不使用GCD API,我宁愿推荐NSOperation和NSOperationQueue API来解决您的特定问题,特别是针对NSOperation.Code更新的可取消性。谢谢你的更正。好的第二个选择
NSOperationQueue
本身由GCD队列支持,尽管这是一个私有实现。上面描述的逻辑基本上是正确的,除了一个小错误,即调度信号量等待(信号量,调度时间永远)应该移动到“for”循环中,就在downloader上面。downloadAsync(图像,…)但是,与使用GCD API不同,我建议您使用NSOperation和NSOperationQueue API来解决这里的特定问题,特别是针对NSOperation的可取消性。代码已更新。谢谢你的更正。好的第二个选择NSOperationQueue
本身由GCD queue支持,尽管这是一个私有实现。