【问题标题】:Published property not updating in SwiftUI已发布的属性未在 SwiftUI 中更新
【发布时间】:2021-12-31 22:14:45
【问题描述】:

我有以下代码,我希望 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 未更新。为什么不呢?

【问题讨论】:

    标签: swiftui publisher


    【解决方案1】:

    for 循环将阻塞主队列,因此创建一个队列以在另一个线程上运行 for i in 1...1000000

        //
        //  ContentView.swift
        //  StackOverFlow
        //
        //  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)
        }
    }
    

    【讨论】:

    • 很好......我已经尝试了 DispatchQueue.main,但如果 for 循环仍在主队列上运行,我想我对 DispatchQueue.main 的使用什么也没做。
    猜你喜欢
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 2020-11-26
    • 2021-01-06
    • 2022-01-04
    相关资源
    最近更新 更多