Предположим, у нас есть некоторый асинхронный код. В какой-то момент мы должны обернуть его в Task {…}, чтобы запустить его из синхронного контекста.
Так где же канонический способ сделать это? ViewModel или ViewController?
Если мы обернем его с помощью Task {…} в ViewModel, функции ViewModel станут эффективно синхронными, и вызов их из ViewController по-прежнему потребует всех этих танцев завершения/делегатов/замыканий/RX для выполнения некоторых обновлений пользовательского интерфейса после завершения асинхронной работы.
С другой стороны, если мы пометим ViewModel функции как async и вызовем их из ViewController внутри Task {…} тела, это, похоже, решит проблему. Так это путь?
Это кажется мне совсем другим вопросом. Вопрос не в том, как вызвать функцию async из синхронной, а в том, где (то есть в контроллере представления или в модели представления).





Я бы не стал повторно вводить устаревшие шаблоны завершения (замыкания, делегаты и т. д.). Это противоречит цели параллелизма Swift — изящному управлению асинхронными зависимостями. Например, в видеоролике Параллелизм Swift: обновление примера приложения на WWDC 2021 показаны примеры того, как мы устраняем обработчики завершения с помощью параллелизма Swift.
Итак, обозначим методы модели асинхронного представления как async. Затем контроллер представления будет использовать Task {…} для входа в асинхронный контекст параллелизма Swift, чтобы он мог await использовать метод async модели представления, а затем запускать обновление пользовательского интерфейса, когда оно будет выполнено.
Но использование Task {…} не ограничивается контроллером представления. Модель представления также может использовать его (например, когда нужно сохранить задачу, чтобы по какой-то причине отменить ее позже).
Но ты спрашиваешь:
если мы пометим
ViewModelфункции какasyncи вызовем их изViewControllerвнутриTask {…}тела, это, похоже, решит проблему. Так это путь?
Именно так. Если метод действительно делает что-то асинхронное, пометьте его как async, и контроллер представления вызовет его из Task {…}.
При всем при этом в проектах SwiftUI, где модель представления часто передает обновления в представление с помощью свойств ObservableObject и @Published, я бы остался в пределах этого интуитивно понятного и естественного шаблона. В этот момент, когда вы решите перейти в асинхронный контекст, становится немного менее убедительным/критичным.
Тем не менее, с точки зрения тестируемости, вы все равно хотите знать, когда асинхронная задача модели представления выполнена, поэтому я, вероятно, все равно сделаю методы модели представления async.
Отвечает ли это на ваш вопрос? Как использовать асинхронность и ожидание для функции по умолчанию?