繁体   English   中英

Swift iOS-如何继续运行与DispatchGroup()结合的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM