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上运行,也许已经有一个库已经存在,但我认为如果没有库,这应该太难实现。缓存不是一个问题。
答案 0 :(得分:1)
如果您对iamgeFromUrl
进行一次小的更改,则只需要包含操作队列和原始imageFromUrl
方法的原始代码。您需要添加几行代码,以确保在下载完成之前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
。