Обновление пользовательского интерфейса после асинхронного вызова ожидания

#swift #async-await #xcode13

Вопрос:

Я загружаю книги из API, показываю индикатор активности при загрузке, обновляю метку после ответа сервера.

 activityView.isHidden = false
        
let task = detach {
    do {
        let books = try await self.bookService.fetchBooks()
        DispatchQueue.main.async {
            self.show(books: books)
        }
    } catch {
        DispatchQueue.main.async {
            self.resultLabel.text = error.localizedDescription
        }
    }
    DispatchQueue.main.async {
       self.activityView.isHidden = true
    }
}

//...
 

Мой вопрос в том, как лучше подходить к обновлению пользовательского интерфейса в основной очереди? DispatchQueue.main.async выглядят уродливо, и я думаю, что есть лучший подход, чтобы сделать то же самое.

Я должен использовать его, потому что все обновления пользовательского интерфейса должны быть в основном потоке, и я получаю ошибки компилятора без DispatchQueue.main.async чего-то вроде

Свойство «текст», изолированное от глобального актора «Главный актер», не может быть изменено из неизолированного контекста

или

Свойство «isHidden», изолированное от глобального актора «MainActor», не может быть изменено из неизолированного контекста

P.S. Используйте Xcode 13.0b2

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

1. MainActor.run

Ответ №1:

Используйте @MainActor вот так —

 self.updateAcitivityIndicator(isHidden: false)
        
let task = detach {
    do {
        let books = try await self.bookService.fetchBooks()
        self.showBooks(books)
    } catch {
        self.showError(error)
    }
    self.updateAcitivityIndicator(isHidden: true)
}

@MainActor
private func showBooks(_ books: [Book]) {
}

@MainActor
private func showError(_ error: Error) {
    self.resultLabel.text = error.localizedDescription
}

@MainActor
private func updateAcitivityIndicator(isHidden: Bool) {
    self.activityView.isHidden = isHidden
}
 

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

1. Эй, Тарун, Что такое @MainActor ? я ничего об этом не знаю, так что, пожалуйста, скажите мне.

2. @jatinfl См. MainActor A singleton actor whose executor is equivalent to the main dispatch queue.

3. поэтому, работая с @MainActor нами, нам не нужно играть с GCD или OprationQueue . Верно?

4. @jatinflэто разные концепции, которые @MainActor были введены с async / await для этой самой цели, которую необходимо решить. Пожалуйста, посмотрите сеансы WWDC 2021 , связанные с параллелизмом Swift, и вы узнаете, что вам нужно.

5. Спасибо за объяснение 🙂