tl;dr 我有一个 OperationQueue,我想同时运行两个操作。这些操作异步下载一些东西,因此它们都会立即被触发,而不是一个接一个地运行。
我通过对每张图片执行以下操作来填充一张非常大的图片表:
public func imageFromUrl(_ urlString: String) {
if let url = NSURL(string: urlString) {
let request = NSURLRequest(url: url as URL)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
if let imageData = data as Data? {
DispatchQueue.main.async {
self.setImageData(imageData)
}
}
});
task.resume()
}
像 imageView.imageFromUrl(...)
一样调用它。
在较慢的互联网连接上,调用会叠加并立即开始加载每个图像。然后,用户必须等待下载的内容相互“打架”,并在所有图像同时(或多或少)出现之前盯着空白屏幕一段时间。如果一个图像接一个图像出现,对用户来说将是一个更好的体验。
我考虑过对项目进行排队,下载列表的第一个,将其从列表中删除并像这样递归调用该函数:
func doImageQueue(){
let queueItem = imageQueue[0]
if let url = NSURL(string: (queueItem.url)) {
print("if let url")
let request = NSURLRequest(url: url as URL)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
print("in")
if let imageData = data as Data? {
print("if let data")
DispatchQueue.main.async {
queueItem.imageView.setImageData(imageData)
self.imageQueue.remove(at: 0)
if(self.imageQueue.count>0) {
self.doImageQueue()
}
}
}
});
task.resume()
}
}
这确实会一个接一个地加载图像,我认为一次至少运行 2 个请求是浪费时间。让我当前的实现同时处理 2 个图像会导致大的意大利面条代码,所以我研究了 Swift 的 OperationQueue
。
我愿意
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2
for (all images) {
queue.addOperation {
imageView.imageFromUrl(imageURL
}
}
但这也会一次触发所有调用,可能是由于请求异步运行并且方法调用在等待图像下载之前结束。我该如何处理?该应用程序还将在 watchOS 上运行,也许已经有一个库,但我认为如果没有库,这应该不会太难实现。缓存不是问题。
最佳答案
如果您对 imageFromUrl
做一个小的更改,您的原始代码和操作队列和您的原始 iamgeFromUrl
方法就是您所需要的。您需要添加几行代码以确保 imageFromUrl
在下载完成之前不会返回。
这可以使用信号量来完成。
public func imageFromUrl(_ urlString: String) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let semaphore = DispatchSemaphore(value: 0)
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
semaphore.signal()
if let imageData = data as Data? {
DispatchQueue.main.async {
self.setImageData(imageData)
}
}
});
task.resume()
semaphore.wait()
}
}
如现在所写,imageFromUrl
只会在下载完成后返回。这现在允许操作队列正确运行 2 个所需的并发操作。
另请注意,代码已修改以避免使用 NSURL
和 NSURLRequest
。
关于Swift:OperationQueue - 在开始下一个之前等待异步调用完成(一次最多运行 2 个 URLRequests),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49708802/