已发布 属性 未在 SwiftUI 中更新

Published property not updating in SwiftUI

我有以下代码,我希望对 Published 属性 标签的更新反映在 UI 中,但事实并非如此。

  public class ViewSearch {
    @ObservedObject var viewModel: ViewModel
  
  /// Main initializer for instance.
  /// - Parameter viewModel: The  view model for searching.
  public init(viewModel: ViewModel) {
    self.viewModel = viewModel
  }
  
  func doSomething()  {
    for i in 1...1000000 {
      if i % 250000  == 0 {
        viewModel.label = "value: \(i)"
      }
    }
    viewModel.label = "Done!"
  }
}

public class ViewModel: ObservableObject {
  @Published public var label = "initial value" {
    didSet {
      print("\(label)")
      self.objectWillChange.send()
    }
  }
  @Published public var searchText = ""
  
  var search: ViewSearch? = nil
}

struct ContentView: View {
  @ObservedObject var model: ViewModel

  var body: some View {
    TextField("Search", text: $model.searchText) { isEditing in
      if isEditing  {
        model.label = "initial value"
      }
    } onCommit: {
      if !model.searchText.isEmpty {
        model.search = ViewSearch(viewModel: model)
        model.search?.doSomething()
      }
    }

    Text(model.label)
  }
}

更新在提交文本字段输入时触发。我希望 UI 显示“值:250000”、“值:500000”等。didSet 观察器显示更改但 UI 未更新。为什么不呢?

for 循环将阻塞主队列,因此在另一个线程

上创建一个队列 运行 for i in 1...1000000
    //
    //  ContentView.swift
    //  Whosebug
    //
    //  Created by Mustafa T Mohammed on 12/31/21.
    //

import SwiftUI

public class ViewSearch {
    @ObservedObject var viewModel: ViewModel

        /// Main initializer for instance.
        /// - Parameter viewModel: The  view model for searching.
    public init(viewModel: ViewModel) {
        self.viewModel = viewModel
    }
    func doSomething()  {
        let q = DispatchQueue.init(label: "doSomething")
            // for loop will block the main queue so create a queue to run for i in 1...1000000
            // on another thread
        q.async { [weak self] in // weak self to prevent retain cycle
            guard let self = self else { return }
            for i in 1...1000000 {
                if i % 250000  == 0 {
                    DispatchQueue.main.async { //update UI by coming back to main thread
                        self.viewModel.label = "value: \(i)"
                    }
                }
            }
            DispatchQueue.main.async { //update UI by coming back to main thread
                self.viewModel.label = "Done!"
            }
        }
    }
}

public class ViewModel: ObservableObject {
    @Published public var label = "initial value" {
        didSet {
            print("\(label)")
            self.objectWillChange.send()
        }
    }
    @Published public var searchText = ""

    var search: ViewSearch? = nil
}

struct ContentView: View {
    @ObservedObject var model: ViewModel

    var body: some View {
        TextField("Search", text: $model.searchText) { isEditing in
            if isEditing  {
                model.label = "initial value"
            }
        } onCommit: {
            if !model.searchText.isEmpty {
                model.search = ViewSearch(viewModel: model)
                model.search?.doSomething()
            }
        }

        Text(model.label)
    }
}