SwiftUI - 确保从主线程发布值(通过像 receive(on :)) on model updates

标签 swiftui combine

我的应用程序包含一个资源繁重的操作,该操作根据从 XML 提要中提取的数据填充数组。我不希望此操作锁定主线程(以及为数组提供新数据时的 UI),因此它在后台完成。

    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] = [] 时,会发生运行时错误。

不允许从后台线程发布更改;确保在模型更新时从主线程发布值(通过像 receive(on:) 这样的操作符)。

我知道这与采用Combine有关,但老实说我不知道​​从哪里开始。任何帮助,将不胜感激。

我只是希望发生以下情况:
  • 用户按下按钮启动 XML 数据拉取填充 myArray
  • myArray 填充在后台线程上,保持 UI 响应
  • 任务完成后,MyView 中的列表会自动更新。目前,我必须离开 View 并再次返回以刷新列表。
  • 最佳答案

    由于追加发生在循环中,因此您需要决定是要为每个项目发出一次新值,还是为整个更新发出一次新值。如果您不确定,请为整个更新更新一次。

    然后在主队列上执行该操作:

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

    关键是你不能在多个队列上读取或写入属性。在这种情况下,您要使用的队列是主要队列(因为它驱动 UI)。因此,您必须确保所有属性访问都发生在该队列上。

    关于SwiftUI - 确保从主线程发布值(通过像 receive(on :)) on model updates,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61108947/

    相关文章:

    ios - onTapGesture禁用我的“选择器”和“分割”点击

    ios - 创建一个 Combine 的发布者,例如 RxSwift 的 Observable.Create 用于 Alamofire 请求

    SwiftUI 发布的更新不刷新

    swift - 'Publishers.Once' 的替代方案是什么?

    ios - SwiftUI:扩大/缩小列表单元格

    ios - 尝试使用几何阅读器和导航栏获得全宽 View - SwiftUI

    SwiftUI:无法推断通用参数 'Subject'

    swift - mixLatest 在 Just 与 Future 中具有不同的行为

    ios - 在 SwiftUI 中运行时创建控件

    uiviewcontroller - 为什么 NavigationLink 按钮在自定义 UIViewControllerRepresentable 包装器中显示为 "disabled"