我的应用程序包含一个资源繁重的操作,该操作根据从 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 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/