Цикл не завершает циклы с очередью отправки, iOS, Swift - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть функция, которая запускает цикл, запускает другую функцию для каждого элемента в цикле, но, похоже, она запускается не так часто, как количество элементов в массиве.

Вот мои функции.

func startLoop(completion: @escaping (_ finished: Bool) -> ()) {


    print("Tony items amount is \(tempImgUrls.count)")
        for item in tempImgUrls {
            dispatchGroup.enter()
            print("Tony begin loop")
            let img = item["imgUrl"]
            let name = item["name"]
            downloadImages(img: img!, name: name!, completion: { (complete) in
                print("Tony mid loop")
                self.dispatchGroup.leave()
            })
        }

    dispatchGroup.notify(queue: DispatchQueue.main) {
        print("Tony end loop")
        completion(true)
        }
    }

func downloadImages(img: String, name: String, completion: @escaping (_ finished: Bool) -> ()) {


            imageShown.sd_setImage(with: URL(string: img), completed: { (image, error, cacheType, imageUrl) in

                let personImg = image!
                let personId = name
                let post = Person(personImage: personImg, personId: personId)

                self.finalImgUrls.append(post)
                completion(true)
                print("Tony array is with images person is \(self.finalImgUrls)")
                print("Tony items 2 amount is \(self.finalImgUrls.count)")

        })
    }
}

И это распечатка в консоле, как вы можете видеть, она печатает начало цикла сначала, затем в середину 1 и в конец 1 раз с одним элементом в конце вместо 4, как напримерчто подается.

Количество элементов Tony равно 4

Tony begin loop

Tony begin loop

Tony begin loop

Тони начало цикла

Тони середина цикла

Массив Тони с изображениями персонажа [AppName.Person]

Тони элементов 2 сумма составляет 1

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Когда вы используете UIImageView расширения поиска асинхронного изображения, они неизменно отменяют предыдущий запрос для этого представления изображения при запросе другого изображения для того же представления изображения. (Как правило, это предусмотрено проектом, так как он предотвращает засорение запроса изображений запросами предыдущих изображений для того же представления изображений, которые больше не нужны, например, представление изображений в ячейке табличного представления, которое можно использовать повторно.)

Проблема в том, что расширение UIImageView SDWebImage не вызывает обработчик завершения, если поиск изображения был отменен. Это ошибка разработки API, IMHO, поскольку асинхронные методы всегда должны вызывать обработчик их завершения (с «отмененным» кодом ошибки, если запрос был отменен). Но поскольку SDWebImage этого не делает, первоначальные запросы вашего цикла отменяются вместо последующих запросов, и в результате ваши leave вызовы для более ранних итераций никогда не будут вызваны. К вашему сведению, другие библиотеки изображений, такие как KingFisher , не страдают этим недостатком дизайна (хотя и имеют свои собственные проблемы).

Но возникает вопрос о том, каково было ваше намерение. Например, если вы хотите увидеть последовательность изображений последовательно, то вам не следует начинать поиск следующего изображения до тех пор, пока не будет выполнено предыдущее (например, начать поиск следующего изображения в обработчике завершения предыдущего). Или, возможно, вам следует просто получить изображения самостоятельно (не используя расширение UIImageView, которое отменяет предыдущие запросы) и выполнить там некоторое обновление вашего пользовательского интерфейса. Но вы почти наверняка не хотите инициировать несколько одновременных обновлений изображений для одного и того же представления изображений.

0 голосов
/ 16 ноября 2018

Код у вас там работает. Кажется, проблема в том, что sd_setImage дает результат только один раз.

Как проверить

Если вы используете тестовую реализацию sd_setImage следующим образом, вы получите ожидаемый результат:

class SomeClass {
    func sd_setImage(with url: URL?, completed: @escaping (UIImage?, Error?, String, URL) -> Void) {
        let random = Double(arc4random()) / Double(UINT32_MAX)
        DispatchQueue.main.asyncAfter(deadline: .now() + random, execute: {
            completed(UIImage(), nil, "a", url!)
        })
    }
}
...