Синхронизация рабочей задачи и контроллера просмотра хода выполнения в swift

#ios #swift #async-await #concurrency #swift5.5

Вопрос:

Я рефакторингую/переписываю некоторый код в устаревшем приложении, в котором (иногда) выполняется длительный запрос. Пользовательский контроллер представления используется для отображения хода выполнения, и когда запрос завершен, отображается другой контроллер представления для результата.

Текущий код представляет VC хода выполнения, затем запускает задачу для запроса, и когда запрос завершен, он представляет результат VC. Проблема в том, что индикатор выполнения отклоняется «автоматически», когда задача запроса отправляет уведомление об успешном выполнении через Центр уведомлений. Излишне говорить, что это не очень стабильно, и много раз VC прогресса не отклоняется вовремя до представления результата VC, что приводит к печати строгого журнала с iOS и отсутствию результата VC.

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

Подводя итог, скажу, что это моя текущая идея, но я не очень доволен тем, что у меня есть отдельная задача только для синхронизации. В «нормальной» среде параллелизма я бы использовал двоичный семафор или что-то подобное, есть ли более чистое решение в Swift? Я ищу способ сообщить Задаче о том, что был вызван обработчик завершения для present() метода -.

 let t = Task {  // Wait longer than present(animated: true) time  try await Task.sleep(nanoseconds: 10_000_000_000) }  let controller = UIAlertController(title: "Progress", message: nil, preferredStyle: .alert) self.present(controller, animated: true, completion: { t.cancel() })  Task {  // Perform work that may take less or more time than presentation  try await Task.sleep(nanoseconds: 10_000_000)    // Wait until alert is fully presented (no wait if work time was long enough)  let _ = await t.result   // Cleanup  controller.dismiss(animated: true, completion: nil)    // Present work result view controller  // ... }  

Комментарии:

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