如何使用 swift 并发模型从 SwiftUI 视图安全地访问 Core 数据 NSManagedObject 属性?

How to safely access Core data NSManagedObject attributes from a SwiftUI view using swift concurrency model?

提问人:ngb 提问时间:11/13/2023 最后编辑:ngb 更新时间:11/14/2023 访问量:63

问:

如何使用 swift 并发模型从 SwiftUI 视图安全地访问核心数据 NSManagedObject 属性。

我的理解是,我们需要将对NSManageObject属性的任何访问都包含在其中,但是如果我在视图中的任何位置使用它,无论是在or或修饰符中,我都会收到以下警告或错误:await context.perform {}.body(),init().task()

for 修饰符或(如果在任何范围内).task{}Task {}:

在主执行组件隔离的上下文之外传递不可发送类型“NSManagedObjectContext.ScheduledTaskType”的参数可能会引入数据争用 即使我仅为此访问创建新上下文,也会发生这种情况。

如果在 或body()init():

“await”在不支持并发的函数中

但是我们不能将 body 或 init() 设置为异步

代码示例如下:

var attributeString: String = ""
let context = PersistentStore.shared.persistentContainer.newBackgroundContext()
await context.perform {
    let backgroundObject = context.objectWithID(objectID)
    attributeString = backgroundObject.attribute!
}
swiftui 核心数据 swift 并发

评论

0赞 ngb 11/13/2023
给出相同的警告/错误。我仍然需要第二行来访问该属性。如果我这样做,让attirbuteString = await context.perform { return nsmanagedObject.attribute! }顺便说一句,我打开了并发编译器标志以查看这些错误/警告。
0赞 lorem ipsum 11/13/2023
我的猜测是您可能将异步等待与GCD或完成处理程序混合在一起

答:

1赞 Joakim Danielson 11/13/2023 #1

你的代码不完整,但像这样的东西应该可以工作。创建一个函数来执行提取,这个函数也是你创建后台上下文的地方

func fetchObject(/* params... */) async -> SomeManagedObject {
    let context = PersistentStore.shared.persistentContainer.newBackgroundContext()
    return await context.perform {
         /* fetch */

         return fetchedObject
    }
}
    

然后在视图中调用该函数并使用它

.task {
    let managedObject = await fetchObject(/* params */)
    attributesString = managedObject.attribute
1赞 malhal 11/13/2023 #2

诀窍是获取 before your perform 块,然后在 perform 中,您只需要使用该 ID 在后台上下文中再次找到对象。现在,您有一个可以从后台安全访问的对象,例如nsmanagedObject.objectID


let objectID = nsmanagedObject.objectID
var attributeString: String = ""
let context = PersistentStore.shared.persistentContainer.newBackgroundContext()
await context.perform {
    let backgroundObject = context.objectWithID(objectID)
    attributeString = backgroundObject.attribute!
}

评论

0赞 ngb 11/14/2023
你是对的,我需要使用对象 ID 来重新获取我忽略的对象,将其包含在问题的简化代码中,当它在视图之外时,这有效。但是在 SwiftUI 视图中,警告/错误位于 await context.perform 行上。
0赞 malhal 11/14/2023
.task 是放置异步代码的地方,对我有用