iOS - 下载多张图片时超时异常

时间:2016-08-02 05:54:05

标签: ios swift asynchronous grand-central-dispatch

首先,让我解释一下我的所作所为。我需要在MKMapView上用图像绘制几百个注释。我的客户提供了一个SDK,它给了我近100个对象,我应该在Map上显示。

这是我从SDK获取项目的方式

SDKRequest.Request(request) { (items, error) -> Void in
            dispatch_async(dispatch_get_main_queue(), {
            // Update UI
            })
            }.execute()
    }

每个项目都有title,id,image等属性。要获取图像,SDK有一个API

item!.loadImage(/*desired size*/) { (image, error) -> Void in
            dispatch_async(dispatch_get_main_queue(), {
                // Update UI
            })
        }

我得到近100件物品并下载与物品相关的图像,我运行了一个for循环。当一次性发送所有100个下载图像的请求时,在下载大约30-40个图像后,我得到请求超时异常。

成功下载图像后,我将图像设置为相应的注释,然后将其添加到Map。最后,我最终导致在地图上添加30-40个项目(满分100个)。

要解决这个问题,我可以将它作为一个递归功能而不是一个真正的想法。

那么,为了处理这种情况,我将如何规范这种多次下载,最佳方式?

2 个答案:

答案 0 :(得分:0)

要下载100张图片并存储,这不是一个好主意。您也可以通过缓存来完成。您可以显示缩略图图像,直到图像下载。您可以通过AFNetworking+UIImageView类别轻松实现它,并且可以使用其他类。如果已经请求了图像网址并且它已被缓存,则它将执行相同的操作,然后它将不会再次下载并为您提供更好的性能。

答案 1 :(得分:0)

如果没有某种节流机制,它不是每个图像发送请求的最佳实现。这可能是你超时的原因。

Dispatch Semaphores 非常适合批量处理。 Dispatch Semaphores仅在需要阻塞调用线程时才调用内核。如果调用信号量不需要阻塞,则不会进行内核调用。

Apple Developer Library - Dispatch Semaphores

semaphore = dispatch_semaphore_create(10) // 10 being number of simultaneous operations.

// Tasks in serial queues execute one at a time.
// Each task starting only after the preceding task has finished. 
// Serial queues are also known as private dispatch queues.

serialQueue = dispatch_queue_create("imageProcessingQueue", DISPATCH_QUEUE_SERIAL)
dispatch_async(serialQueue) {
for image in annotationImages {
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) // block if 10 images downloading
    downloader.downloadAsync(image, ...) { // completion
          dispatch_semaphore_signal(semaphore)
          // handle annotation images or error
          // add downloaded annotation images to...
    }
  }
}

之后,您将计算剩余的操作并在完成后实现完成处理程序。或小组行动等。

dispatch_async(serialQueue) {
dispatch_async(main_queue()) {...stuff...}
}

使用NSOperationNSOperationQueue

的第二个选项

如果您想按照下面的建议尝试NSOperationNSOperationQueue Ray Wenderlich有一个很好的教程。

NSOperationNSOperationQueue建立在GCD之上。与GCD相比,NSOperation增加了一些额外开销,但您可以在各种操作中添加依赖关系并重新使用,取消或暂停它们。

正如RW页面所示,代码看起来像这样。用例不同,但这是没有递归的一般想法。

Operations.swift

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)
}