vc1 pushes on vc2 and in vc2.
In vc2 I have an array of strings that I convert to urls which eventually go through a URLSession and the images returned get converted to images with filters. Once I get the filtered image in the URLSession callback I save it to cache.
I want the filtered images that are returned to be displayed in the exact order that is in the array of strings. I followed this answer and use DispatchGroup + Semaphores and everything works fine, the order of the filtered images are returned in the exact order.
The problem I ran into is if the user returns back to vc1 then pushes on vc2, once the code below runs and sees that the cache has the first filtered image ("str1"), it adds it to the filteredArray and jumps to dispatchGroup.notify
. The filtered images associated with "str1" from the array is the only thing that is appended and the images from "str2" and "str3" aren't.
The cache might or might not have purged the filtered images associated with "str2", "str3" and if it did purge them then the loop should continue to the URLSession callback but it doesn't. But if it didn't purge them it also doesn't add them. That is where my problem occurs, the loop stops running once the cache is hit. This is my first time using a semaphore so I'm not sure where the issues is arising from.
What I did to get around the problem was I simply removed the cache and everything works fine but that also means I don't get the benefit of using the cache.
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
}
}