SwiftUI - убедитесь, что публикуете sh значений из основного потока (через операторы, такие как receive (on :)) при обновлении модели - PullRequest
0 голосов
/ 08 апреля 2020

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

    let dispatchQueue = DispatchQueue(label: "concurrent.queue", qos: .utility, attributes: .concurrent)
    class XMLHandler: ObservableObject {
    let context: NSManagedObjectContext
    @Published var myArray: [CustomObject] = []
     init(context: NSManagedObjectContext) {
        self.context = context
    }
    ...some code...
      func populateArray {
      dispatchQueue.async {
       ...xml parsing happens...
       (xmlOutputObject) in 
          for x in xmlOutputObject {
                            self.myArray.append(x) }
    }

В другом месте мой SwiftUI View использует myArray для заполнения списка:

struct MyView: View {

 @EnvironmentObject var handler: XMLHandler
    var body: some View {
            List{
                ForEach(handler.myArray) { CustomObject in
              ... generate rows ...
                    }
                }
            }

Моя ошибка во время выполнения возникает, когда мое приложение пытается обновить @Published var myArray: [CustomObject] = [].

Публикация изменений из фоновых потоков не допускается; Обязательно публикуйте sh значения из основного потока (через операторы, такие как receive (on :)) при обновлении модели.

Я знаю, что это как-то связано с принятием Combine, но я честно понятия не имею, с чего начать. Мы будем благодарны за любую помощь.

Я просто хочу, чтобы произошло следующее:

  1. Пользователь нажимает кнопку, которая запускает XML извлечение данных, которое заполняет myArray
  2. myArray заполняется в фоновом потоке, поддерживая отзывчивость пользовательского интерфейса
  3. Список в MyView автоматически обновляется по завершении задачи. В настоящее время мне нужно отойти от вида и вернуться назад, чтобы список обновился sh.

1 Ответ

1 голос
/ 08 апреля 2020

Поскольку добавление происходит в al oop, вам необходимо решить, хотите ли вы выдавать новое значение один раз для элемента или один раз для всего обновления. Если вы не уверены, обновите его один раз для всего обновления.

Затем выполните это действие в главной очереди:

  ...xml parsing happens...
   (xmlOutputObject) in 
      DispatchQueue.main.async {   // <====
          self.append(contentsOf: xmlOutputObject)
      }

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

...