Swift iOS -Как продолжить запуск DispatchSemaphore в сочетании с DispatchGroup () - PullRequest
0 голосов
/ 29 апреля 2019

vc1 выдвигает на vc2 и в vc2.

В vc2 у меня есть массив строк, которые я конвертирую в URL, которые в конечном итоге проходят через URLSession, а возвращаемые изображения преобразуются в изображения с фильтрами.Как только я получаю отфильтрованное изображение в обратном вызове URLSession, я сохраняю его в кеше.

Я хочу, чтобы отфильтрованные изображения, которые были возвращены, отображались в точном порядке, который находится в массиве строк.Я следовал за этим ответом и использую DispatchGroup + Семафоры, и все работает нормально, порядок отфильтрованных изображений возвращается в точном порядке.

Проблема, с которой я столкнулся, заключается в том, что если пользователь возвращается обратнок vc1, затем нажимает на vc2, когда приведенный ниже код запускается и видит, что в кеше есть первое отфильтрованное изображение ("str1"), он добавляет его в FilterArray и переходит к 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
    }
}

1 Ответ

0 голосов
/ 29 апреля 2019

Во время первого нажатия второго VC все изображения не находятся в кеше, поэтому никакие защитные механизмы не запускаются, а также 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
}
...