![](/img/trans.png)
[英]Swift wait for existing async operation to finish before starting a new one
[英]Swift: OperationQueue - wait for asynchronous calls to finish before starting next (have maximum of 2 URLRequests running at a time)
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(...)
那樣調用它。
在較慢的Internet連接上,呼叫會堆疊起來,並立即開始加載每個圖像。 然后,用戶必須等待下載內容相互“打架”,並在空白圖像全部一次(或多或少)出現之前凝視空白屏幕。 如果一個圖像接一個出現,對於用戶來說將是一個更好的體驗。
我考慮過將項目排隊,下載列表的第一個,從列表中刪除它,然后像這樣遞歸調用函數:
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
進行少量更改, imageFromUrl
需要帶有操作隊列的原始代碼和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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.