Swift:OperationQueue - 在开始下一个之前等待异步调用完成(一次最多有 2 个 URLRequests 运行)
Swift: OperationQueue - wait for asynchronous calls to finish before starting next (have maximum of 2 URLRequests running at a time)
tl;dr 我有一个 OperationQueue,我想同时进行两个操作 运行ning。这些操作异步下载一些东西,因此它们都会立即触发,而不是 运行 一个接一个地触发。
我通过对每个图像执行以下操作来填充 table 个非常大的图像:
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(...)
一样称呼它。
在较慢的互联网连接上,调用会叠加并立即开始加载每张图片。然后,用户必须等待下载到 "fight" 彼此,并且在所有图像一次(或多或少)出现之前盯着空白屏幕一段时间。如果一个图像一个接一个地出现,对用户来说会是一个更好的体验。
我考虑过排队项目,下载列表的第一个,将其从列表中删除并像这样递归调用函数:
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 个请求 运行ning 是浪费时间。让我当前的实现同时处理 2 个图像会导致大的意大利面条代码,所以我研究了 Swift 的 OperationQueue
。
我愿意
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2
for (all images) {
queue.addOperation {
imageView.imageFromUrl(imageURL
}
}
但这也会同时触发所有调用,可能是因为请求 运行 异步并且方法调用在等待图像下载之前结束。我该如何处理?该应用程序还将在 watchOS 上 运行,也许已经有一个库,但我认为如果没有库,这应该不会太难实现。缓存不是问题。
如果您对 imageFromUrl
做一点小改动,您只需要包含操作队列的原始代码和原始 iamgeFromUrl
方法。您需要添加几行代码以确保 imageFromUrl
在下载完成之前不会 return。
这可以使用信号量来完成。
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
下载完成后只会 return。这现在允许操作队列正确地 运行 2 个所需的并发操作。
另请注意代码已修改以避免使用 NSURL
和 NSURLRequest
。
tl;dr 我有一个 OperationQueue,我想同时进行两个操作 运行ning。这些操作异步下载一些东西,因此它们都会立即触发,而不是 运行 一个接一个地触发。
我通过对每个图像执行以下操作来填充 table 个非常大的图像:
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(...)
一样称呼它。
在较慢的互联网连接上,调用会叠加并立即开始加载每张图片。然后,用户必须等待下载到 "fight" 彼此,并且在所有图像一次(或多或少)出现之前盯着空白屏幕一段时间。如果一个图像一个接一个地出现,对用户来说会是一个更好的体验。
我考虑过排队项目,下载列表的第一个,将其从列表中删除并像这样递归调用函数:
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 个请求 运行ning 是浪费时间。让我当前的实现同时处理 2 个图像会导致大的意大利面条代码,所以我研究了 Swift 的 OperationQueue
。
我愿意
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2
for (all images) {
queue.addOperation {
imageView.imageFromUrl(imageURL
}
}
但这也会同时触发所有调用,可能是因为请求 运行 异步并且方法调用在等待图像下载之前结束。我该如何处理?该应用程序还将在 watchOS 上 运行,也许已经有一个库,但我认为如果没有库,这应该不会太难实现。缓存不是问题。
如果您对 imageFromUrl
做一点小改动,您只需要包含操作队列的原始代码和原始 iamgeFromUrl
方法。您需要添加几行代码以确保 imageFromUrl
在下载完成之前不会 return。
这可以使用信号量来完成。
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
下载完成后只会 return。这现在允许操作队列正确地 运行 2 个所需的并发操作。
另请注意代码已修改以避免使用 NSURL
和 NSURLRequest
。