获取 NSManagedObject 实例的上下文是不是是线程安全的?
Posted
技术标签:
【中文标题】获取 NSManagedObject 实例的上下文是不是是线程安全的?【英文标题】:Is it thread safe to get context of NSManagedObject instance?获取 NSManagedObject 实例的上下文是否是线程安全的? 【发布时间】:2021-09-16 16:34:04 【问题描述】:即从其他线程访问 NSManagedObject 的managedObjectContext
属性?例如:
class StoredObject: NSManagedObject
@NSManaged public var interestProperty: String
------- somewhere on background -------
let context = storedObject.managedObjectContext // is it safe?
context.perform [storedObject] in
// do something with interestProperty
---------------------------------------
【问题讨论】:
你为什么需要这个?NSManagedObjectContext
不是线程安全的,那么你会在另一个线程上用它做什么?
legacy) 已知objectID
属性是线程安全的,但我不确定managedObjectContext
。无论如何,即使有 -com.apple.CoreData.ConcurrencyDebug 1
标志,也没有引发任何异常。
【参考方案1】:
NSManagedObjectContext
不是线程安全的。即使您获取此类对象的实例,在不同的线程上使用它也可能导致未定义的行为。
这是在 Apple documentation 中指定的(重点是我的):
Core Data 旨在在多线程环境中工作。然而,并不是 Core Data 框架下的每个对象都是线程安全的。要在多线程环境中使用 Core Data,请确保:
托管对象上下文在初始化时绑定到与其关联的线程(队列)。
从上下文中检索的托管对象绑定到上下文所绑定的同一个队列。
因此,虽然读取managedObjectContext
属性可能是线程安全的,因为该属性是只读的,您将无法使用它而不会冒竞争条件的风险。而且您还需要考虑托管对象的生命周期,因为除非正确保留,否则您最终可能会向已释放的托管对象询问其上下文。
【讨论】:
不错的答案。但是,由于托管对象可能处于“故障”状态,我不会对“只读”属性下太多赌注:它可能在该代理初始化后设置,何时实现.如果是这种情况,或者可能是这种情况,访问此类只读属性不是线程安全的。不知道源代码,我们不知道;) 关于“故障”状态的@CouchDeveloper 很好,这是避免使用托管上下文的另一个原因。从理论上讲,甚至不需要这样做,自然方向是托管上下文->托管对象,反之亦然。 @CouchDeveloper 错误适用于从持久存储中读取的属性。托管对象上下文不是这些属性之一,因此错误不会影响访问是否安全。 没有“解除分配”托管对象之类的东西。托管对象可能会成为故障,但这并不意味着它们会被释放。它们确实存在,您可以访问它们。NSManagedObject.managedObjectContext
的主要问题是,如果对象与上下文解除关联,它会变成 nil
。但如果你能保证它不会发生,那么抓住上下文并对其执行工作绝对没有错。
@Cristik 同意。理想情况下,应该传递对象 ID,然后在需要时构造托管对象。以上是关于获取 NSManagedObject 实例的上下文是不是是线程安全的?的主要内容,如果未能解决你的问题,请参考以下文章
为 NSManagedObject 创建实例但不将其保存到上下文中
从 NSManagedObject 中检索 NSManagedObjectContext
无论当前上下文状态如何,如何获取 NSManagedObject 的持久存储副本