NSManagedObjectContext 的 userInfo 属性是如何工作的?

Posted

技术标签:

【中文标题】NSManagedObjectContext 的 userInfo 属性是如何工作的?【英文标题】:How does NSManagedObjectContext's userInfo property work? 【发布时间】:2014-10-05 19:01:18 【问题描述】:

在当前的头文件中,它被声明为:

@property (nonatomic, readonly, strong) NSMutableDictionary *userInfo NS_AVAILABLE(10_7,  5_0);

文档只是说:

返回接收者的用户信息。

    上下文的userInfo 的用途是什么? Other Core Data objects 具有可以在托管对象模型中设置的 userInfo 字典。这似乎不是这里的情况。它只是一个临时存储,比使用关联对象更方便吗?

    它是否曾经保存到持久存储或通过NSCoding

    它是否使用与上下文的托管对象相同的线程模型?

【问题讨论】:

这是一个很好很有趣的问题。 【参考方案1】:

上下文的 userInfo 的用途是什么?

我看了这几种方法,不幸的是没有找到任何确定的东西。

-[NSManagedObjectContext userInfo] 上设置一个符号断点并运行一组核心数据回归测试,这些测试运行大部分公共 API。 使用多个逆向工程工具查看了 Core Data 二进制框架。

使用符号断点并没有产生太大的影响,尽管我使用的 Xcode 版本有可能刚刚超过它。似乎没有任何东西在访问公共访问器,但考虑到 Core Data 的内部结构,这并不令人惊讶。

反汇编该方法产生了一些提示:

void * -[NSManagedObjectContext userInfo](void * self, void * sel) 
    rsi = sel;
    rbx = self;
    if (*(int32_t *)__PF_Threading_Debugging_level != 0x0) 
            __PFAssertSafeMultiThreadedAccess_impl(rbx, rsi);
    
    rax = *_OBJC_IVAR_$_NSManagedObjectContext._additionalPrivateIvars;
    rax = *(rbx + rax);
    rax = *(rax + 0x30);
    return rax;

该方法确实检查并发调试是否处于活动状态,以及该方法是否在并发规则中正确使用(这回答了问题 3)。该方法是直接访问私有实例变量_additionalPrivateIvars,Core Data 的其他部分从中读取和写入。一些更改跟踪/推进和乐观锁定方法使用此实例变量。例如,-lockObjectStoreNSManagedObjectContext 上写信给_additionalPrivateIvars

有点奇怪,NSMutableDictionary 是只读的。您无法设置新的NSMutableDictionary,但您可以愉快地在其上设置键和值。我能够很容易地做到这一点:

(lldb) po [[[result managedObjectContext] userInfo] setValue:@"foo" forKey:@"bar"]
0x0000000000000020

(lldb) po [[result managedObjectContext] userInfo]

    bar = foo;

如果没有来自 Apple 的更详细的指导,我不想在生产代码中这样做,因为这样写可能很危险。

它是否曾经保存到持久存储或通过 NSCoding?

似乎没有,这样做没有多大意义。持久存储对通过协调器访问它们的上下文知之甚少,如果 userInfo 字典对存储很重要,则应在原子存储编程指南和增量存储编程指南中进行介绍。

它是否使用与上下文的托管对象相同的线程模型?

确实如此,如果并发调试是主动滥用-userInfo 将记录一个断言。

【讨论】:

感谢您对此进行调查。我投了赞成票,但仍然希望得到更明确的答案。 最好的办法是在 Apple 论坛上提问,或者在课程文档中发布雷达请求更多详细信息。【参考方案2】:

关于这个特定 API 的文档非常少(总文本为:The receiver’s user info.)。但是,userInfo 字典在 Apple 的框架中是非常标准的。用户无需创建子类即可添加自定义信息(例如,请参阅NSNotificationuserInfo 上的documentation)。

NSManagedObjectContextuserInfo 是只读的这一事实不是问题。而不是像您期望的那样将属性分配给字典:

// useful while debugging multiple Core Data threads
*moc.userInfo = @@"name":@"main managed object context";

直接访问字典(毕竟它是可变的):

*moc.userInfo[@"name"] = @"main managed object context"

【讨论】:

以上是关于NSManagedObjectContext 的 userInfo 属性是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

NSManagedObjectContext:自动更新与否?

父/子 NSManagedObjectContext 不起作用

如何清除 NSManagedObjectContext 中的所有对象?

CoreData 多 NSManagedObjectContext 保存通知说明

NSManagedObjectContext: performBlockAndWait vs performBlock 通知中心

NSManagedObjectContext 类别