我的应用程序包含一个资源密集型操作,该操作根据从 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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在其他地方,我的 SwiftUI 视图使用 myArray 来填充它的列表:
struct MyView: View {
@EnvironmentObject var handler: XMLHandler
var body: some View {
List{
ForEach(handler.myArray) { CustomObject in
... generate rows ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我的应用程序尝试更新 @Published var myArray: [CustomObject] = [] 时,会出现运行时错误。
不允许从后台线程发布更改;确保在模型更新时从主线程发布值(通过像 receive(on:) 这样的运算符)。
我知道这与采用合并有关,但老实说我不知道从哪里开始。任何帮助,将不胜感激。
我只是希望发生以下情况:
小智 46
只需放在@MainActor定义应该在主线程中运行的类之前即可。使用新的 Swift 并发性非常简单。
@MainActor class DocumentsViewModel: ObservableObject { ... }
Run Code Online (Sandbox Code Playgroud)
在新的 WWDC 2021 视频或类似文章中,有很多相关信息:Using the MainActor attribute toautomatic split UI updates on the main queue
Rob*_*ier 16
由于追加发生在循环中,因此您需要决定是要为每个项目发出一次新值,还是为整个更新发出一次新值。如果您不确定,请在整个更新过程中更新一次。
然后在主队列上执行该操作:
...xml parsing happens...
(xmlOutputObject) in
DispatchQueue.main.async { // <====
self.append(contentsOf: xmlOutputObject)
}
Run Code Online (Sandbox Code Playgroud)
关键点是您无法读取或写入多个队列上的属性。在本例中,您要使用的队列是主要队列(因为它驱动 UI)。因此,您必须确保所有属性访问都发生在该队列上。
Max*_*eod 13
iOS 期望所有 UI 更改都在主线程上进行。SwiftUI 也不例外。在主线程外执行 UI相关工作是可以接受的,但这些更改迟早需要带到主线程上进行渲染。
\n\xe2\x80\x99t 似乎您正在使用合并。但是,如果你当时出现这个错误;
\n\n\n不允许从后台线程发布更改;确保在模型更新时从主线程发布值(通过像 receive(on:) 这样的运算符)。
\n
最好使用建议的组合调度运算符来解决:
\n.receive(on: DispatchQueue.main)\nRun Code Online (Sandbox Code Playgroud)\n在 Apple\xe2\x80\x99s 中使用调度运算符在调度队列之间移动工作使用合并处理 URL 会话数据任务结果一文中对此进行了详细介绍:
\ncancellable = urlSession\n .dataTaskPublisher(for: url)\n .receive(on: DispatchQueue.main)\n .sink(receiveCompletion: { print ("Received completion: \\($0).") },\n receiveValue: { print ("Received data: \\($0.data).")})\nRun Code Online (Sandbox Code Playgroud)\n
Dav*_*ski 12
DispatchQueue.main.async {
nc.post(name: Notification.Name(NotificationStrings.AccountPostReceived), object: nil)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
36176 次 |
| 最近记录: |