Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS-下载多个图像时超时异常_Ios_Swift_Asynchronous_Grand Central Dispatch - Fatal编程技术网

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支持,尽管这是一个私有实现。