簡體   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