gpt4 book ai didi

ios - Swift iOS - 如何结合 DispatchGroup() 继续运行 DispatchSemaphore

转载 作者:行者123 更新时间:2023-11-29 05:48:36 24 4
gpt4 key购买 nike

vc1 插入 vc2 并进入 vc2。

在 vc2 中,我有一个字符串数组,我将其转换为 url,最终通过 URLSession,返回的图像将转换为带有过滤器的图像。一旦我在 URLSession 回调中获得过滤后的图像,我会将其保存到缓存中。

我希望返回的过滤图像按照字符串数组中的确切顺序显示。我关注了this answer并使用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 会触发

if let cachedImage = imageCache.object(forKey: str as AnyObject) as? UIImage {
....
return
}

并且由于您放置了 return 语句,它将导致 for 循环和函数退出,导致后续的图像捕获结束,从而触发调度组通知,因为有一个相等的此时 enter/leave 的计数,您真正需要的是当缓存中存储有图像或 url 错误时停止使用 session 获取它,这是最好的事情对于 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
}

关于ios - Swift iOS - 如何结合 DispatchGroup() 继续运行 DispatchSemaphore,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55894821/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com