Как убедиться, что все сетевые вызовы были выполнены перед доступом к моей основной модели данных?

Я делаю несколько вызовов API подряд, и когда я, наконец, нажимаю на свой следующий контроллер представления, мои данные полностью пусты из моей базовой модели данных. В ViewController A я сделал следующие запросы в этом порядке:

Api.verifyOtp(email, otp).continueWith { (task) -> Any? in
            if task.succeed {

                self.apiCallOne()
                self.apiCallTwo()
                self.apiCallThree()
                self.apiCallFour()
                self.apiCallFive()

            } else {
                Hud.hide()
                task.showError()
            }
            return nil
        }

Теперь все эти вызовы выполняются асинхронно. Однако последний метод, который является self.apiCallFive(), — это метод, который подталкивает к ViewController B. Вот звонок:

Api.apiCallFive().continueOnSuccessWith { (task) -> Any? in
        Hud.hide()
        if task.succeed {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            let viewB storyboard.instantiateViewController(withIdentifier: "ViewControllerB"                        self.navigationController?.pushViewController(viewB, animated: true)
        }

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

Спасибо!

Я предполагаю, что эти вызовы API также делают что-то вроде записи результатов вызова API в основные данные?

marosoaie 19.04.2019 11:32

Да, они встроены в запросы API. После того, как вызов завершил получение данных, объект создается и сохраняется в основных данных.

butter_baby 19.04.2019 11:33

вы получаете уведомление, когда другой вызов API завершен?

kubrick G 19.04.2019 11:41

Каким бы ни было решение, убедитесь, что вы не зависаете навсегда, если какой-либо из вызовов не работает.

Arkku 19.04.2019 11:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я столкнулся с той же проблемой. Исправьте это, используя DispatchGroup.

Код:

Определить как property

let APIGroup = DispatchGroup()

Выполните приведенный ниже код при запуске любого вызова API.

APIGroup.enter()

Выполните приведенный ниже код, когда любой вызов API завершен.

downloadGroup.leave()

Блокировать уведомления:

APIGroup.notify(queue: DispatchQueue.main) {
    print("All APIs called successfully: Perform required operation")
}

Нет необходимости управлять каким-либо счетчиком или другими переменными. notify автоматически блокировать вызов, когда все задачи выполнены успешно.

What’s really important here is the enter-leave pairs. You have to be very careful and make sure that you leave the group. It would be easy to introduce a bug in the code above. Let’s say that we didn’t leave the group in that guard statement above, just before the return. If the API called failed, or the JSON was malformed, the number of groups> entries would not match the number of leaves. So the group completion handler would never get called. If you’re calling this method from the UI and displaying an activity indicator while your networking requests are running, you would never get a callback from the method, and you would keep on spinning ?

документы Apple

Матерь Божья, это прекрасное решение. Итак, я полагаю, что было бы лучше, если бы операция не удалась, я мог бы либо отобразить сообщение, уведомляющее пользователя о том, что он должен проверить свою сеть, либо любое другое сообщение об ошибке и повторить попытку позже? Кроме того, остановите вращение спиннера;)

butter_baby 19.04.2019 12:15

@butter_baby Рад слышать. Удачного кодирования :)

Hitesh Surani 19.04.2019 12:32

Чтобы решить эту проблему, вам нужен способ получать уведомления о завершении каждого вызова. Самый простой способ сделать это — использовать блоки завершения для каждого вызова.

func apiCall(completion: @escaping () -> Void) {
    ....
}

После добавления блоков завершения к вызовам API ваши блоки могут выглядеть так:

let dispatchGroup = DispatchGroup()

dispatchGroup.enter()
apiCallOne {
    dispatchGroup.leave()
}

dispatchGroup.enter()
apiCallTwo {
    dispatchGroup.leave()
}

...


dispatchGroup.enter()
apiCallN {
    dispatchGroup.leave()
}
dispatchGroup.wait(timeout: Constants.timeout)

Имейте в виду, что оператор wait заблокирует поток, в котором вы его вызываете, пока не будут выполнены все операторы leave(), поэтому будьте осторожны, чтобы не попасть в тупик.

Ах, отлично. На самом деле я вызываю большинство из них из одного класса API, и было бы нецелесообразно вводить группу диспетчеризации внутри этих методов, поскольку они также используются в другом месте моего проекта. Значит, безопасно вызывать dispatchGroup.enter() вне метода, а затем просто dispatchGroup.leave() внутри обработчика завершения?

butter_baby 19.04.2019 12:19

Да, звонить им, как я показал выше, должно быть нормально. Хотя не уверен, что полностью понял ваш вопрос.

marosoaie 19.04.2019 21:18

Другие вопросы по теме