![](/img/trans.png)
[英]Swift 4 async call with for loop execute in order using DispatchGroup, DispatchQueue and DispatchSemaphore
[英]Swift iOS -How to continue running a DispatchSemaphore combined with DispatchGroup()
vc1推送vc2和vc2。
在vc2中,我有一個字符串數組,我轉換為url,最終通過URLSession,返回的圖像轉換為帶過濾器的圖像。 一旦我在URLSession回調中獲得過濾后的圖像,我將其保存到緩存中。
我希望返回的過濾圖像以字符串數組中的確切順序顯示。 我按照這個答案並使用DispatchGroup + Semaphores,一切正常,過濾后的圖像的順序按照確切的順序返回。
我遇到的問題是,如果用戶返回vc1然后按下vc2,一旦下面的代碼運行並看到緩存有第一個過濾的圖像(“str1”),它就會將它添加到filteredArray並跳轉到dispatchGroup.notify
。 與數組中的“str1”相關聯的濾波圖像是唯一附加的圖像,而來自“str2”和“str3”的圖像不是。
緩存可能會或可能不會清除與“str2”,“str3”關聯的已過濾圖像,如果它確實清除了它們,那么循環應該繼續到URLSession回調但它不會。 但如果它沒有清除它們,它也不會添加它們。 這就是我的問題發生的地方,一旦達到緩存,循環就會停止運行。 這是我第一次使用信號量,所以我不確定問題出在哪里。
我解決這個問題的方法是我只是刪除緩存,一切正常,但這也意味着我沒有得到使用緩存的好處。
let imageCache = NSCache<AnyObject, AnyObject>()
let arrOfStringsAsUrls = ["str1", "str2", "str3", "maybe more strings..."]
var filteredArray = [UIImage]()
let dispatchGroup = DispatchGroup()
let dispatchQueue = DispatchQueue(label: "any-label-name")
let dispatchSemaphore = DispatchSemaphore(value: 0)
dispatchQueue.async {
for str in arrOfStringsAsUrls {
dispatchGroup.enter()
guard let url = URL(string: str) else {
dispatchSemaphore.signal()
dispatchGroup.leave()
return
}
if let cachedImage = imageCache.object(forKey: str as AnyObject) as? UIImage {
self?.filteredArray.append(cachedImage)
dispatchSemaphore.signal()
dispatchGroup.leave()
return
}
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if let error = error {
dispatchSemaphore.signal()
dispatchGroup.leave()
return
}
guard let data = data, let image = UIImage(data: data) else {
dispatchSemaphore.signal()
dispatchGroup.leave()
return
}
DispatchQueue.main.async{ [weak self] in
let filteredImage = self?.addFilterToImage(image)
self?.imageCache.setObject(image, forKey: str as AnyObject)
self?.filteredArray.append(filteredImage)
dispatchSemaphore.signal()
dispatchGroup.leave()
}
}).resume()
dispatchSemaphore.wait()
}
dispatchGroup.notify(queue: dispatchQueue) { in
// reloadData() and do some other stuff on the main queue
}
}
在第一次推送第二個VC期間,所有圖像都不在緩存中,因此沒有其他防護觸發器, if let cachedImage = imageCache...
所以一切順利,在下一次推送后緩存存儲了圖像,這樣如果讓觸發器
if let cachedImage = imageCache.object(forKey: str as AnyObject) as? UIImage {
....
return
}
並且由於你輸入了一個return
語句,它將導致for-loop和function的退出,導致后續的圖像捕獲結束,觸發disptach組通知,因為那時有相同的enter
/ leave
計數,什么你真正需要的是當存在緩存中的圖像或者url是錯誤的,以阻止它與會話的獲取,並且for循環中的這個作業的最好的事情是continue
關鍵字,它將跳過當前的迭代並跳轉到下一個
guard let url = URL(string: str) else {
dispatchSemaphore.signal()
dispatchGroup.leave()
continue
}
if let cachedImage = imageCache.object(forKey: str as AnyObject) as? UIImage {
self?.filteredArray.append(cachedImage)
dispatchSemaphore.signal()
dispatchGroup.leave()
continue
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.