Swift iOS - 如何继续 运行 与 DispatchGroup() 结合的 DispatchSemaphore
Swift iOS -How to continue running a DispatchSemaphore combined with DispatchGroup()
vc1 推 vc2 和 vc2。
在 vc2 中,我有一个字符串数组,我将它们转换为 url,最终通过 URLSession,返回的图像被转换为带有过滤器的图像。在 URLSession 回调中获得过滤后的图像后,我将其保存到缓存中。
我希望返回的筛选图像按照字符串数组中的确切顺序显示。我遵循 并使用 DispatchGroup + Semaphores,一切正常,过滤图像的顺序以准确的顺序返回。
我 运行 遇到的问题是,如果用户 returns 回到 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 的第一次推送期间,所有图像都不在缓存中,因此没有 guard else 触发,而且 if let cachedImage = imageCache...
所以一切顺利,在下一次推送后缓存存储了图像,所以如果让触发
if let cachedImage = imageCache.object(forKey: str as AnyObject) as? UIImage {
....
return
}
并且由于您放置了 return
语句,它会导致 for 循环和函数退出,导致后续的图像捕获结束,这会触发调度组通知,因为计数相等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
}
vc1 推 vc2 和 vc2。
在 vc2 中,我有一个字符串数组,我将它们转换为 url,最终通过 URLSession,返回的图像被转换为带有过滤器的图像。在 URLSession 回调中获得过滤后的图像后,我将其保存到缓存中。
我希望返回的筛选图像按照字符串数组中的确切顺序显示。我遵循
我 运行 遇到的问题是,如果用户 returns 回到 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 的第一次推送期间,所有图像都不在缓存中,因此没有 guard else 触发,而且 if let cachedImage = imageCache...
所以一切顺利,在下一次推送后缓存存储了图像,所以如果让触发
if let cachedImage = imageCache.object(forKey: str as AnyObject) as? UIImage {
....
return
}
并且由于您放置了 return
语句,它会导致 for 循环和函数退出,导致后续的图像捕获结束,这会触发调度组通知,因为计数相等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
}