为什么托管对象和上下文之间存在弱引用?

Why is there a Weak References Between Managed Objects and the Context?

当我学习如何使用子上下文时:

 let childContext =
 NSManagedObjectContext(
concurrencyType: .mainQueueConcurrencyType)
 childContext.parent = coreDataStack.mainContext

let childEntry =
childContext.object(with: surfJournalEntry.objectID)
as? JournalEntry
 // 3
detailViewController.journalEntry = childEntry
detailViewController.context = childContext
detailViewController.delegate = self

作者对将托管对象和托管对象上下文都传递给 detailViewController 做了一些评论:

Note: You might be wondering why you need to pass both the managed object and the managed object context to the detailViewController, since managed objects already have a context variable. This is because managed objects only have a weak reference to the context. If you don’t pass the context, ARC will remove the context from memory (since nothing else is retaining it) and the app will not behave as you expect.

嗯,好的,那么请阅读一些官方文档:

This means that in general you cannot rely on a context to ensure the longevity of a managed object instance, and you cannot rely on the existence of a managed object to ensure the longevity of a context. Put another way, just because you fetched an object doesn’t mean it will stay around.

但是,我不明白在托管对象和上下文之间进行弱引用的真正意图是什么?他们追求的目标是什么?

您可以将 managedObject 视为小而愚蠢的对象。他们有一个指向他们上下文的指针并且知道他们的 objectId。当他们需要了解某事时,他们会查询上下文。这有很多非常巧妙的优点。如果一个实体已经在上下文中被查询过,它的第二个实例将命中上下文中的行缓存,而根本不会命中存储。

通常有两种上下文(对于大多数核心数据设置):始终在内存中的长寿命主队列上下文和短寿命后台上下文。对于主队列上下文,您通常不需要担心上下文会离开内存。它们在应用程序的整个生命周期内都保留在内存中。短暂的上下文存在内存不足的问题,并且它们不是线程安全的。所以通常它们应该在正确线程上的块中创建 - 使用然后丢弃并且不会传递出块。

我希望能解释清楚。

托管对象上下文通常对获取的对象使用弱引用以避免过度使用内存的可能性。如果它使用强引用,并且您执行了一个或多个发现大量结果的提取,那么只要上下文存在,所有这些结果都会保留在内存中。在许多应用程序中,这意味着它们永远不会消失,因为在应用程序退出之前上下文一直存在。这可能会导致应用程序为不再使用的对象占用大量内存。弱引用意味着一旦应用程序停止使用托管对象,它们就会被释放。

但在某些情况下您可能需要强引用,因此有一个名为 retainsRegisteredObjects 的布尔值 属性 可以让上下文使用强引用。喜欢就用,注意内存占用

托管对象不保留对其上下文的强引用以避免引用循环。如果它们是强引用并且您将 retainsRegisteredObjects 设置为 true,您将获得一个引用循环。每个对象都会持有对另一个的强引用,因此除非您将其中一个引用设置为 nil,否则它们都不会从内存中释放。