NSManagedObject 的设置属性阻止了核心数据中的 iPad UI'

Posted

技术标签:

【中文标题】NSManagedObject 的设置属性阻止了核心数据中的 iPad UI\'【英文标题】:Setting attribute of NSManagedObject is blocking the iPad UI' in Core DataNSManagedObject 的设置属性阻止了核心数据中的 iPad UI' 【发布时间】:2011-07-18 06:38:29 【问题描述】:

首先,我通过下面粘贴的链接找到了几个与该问题相关的问题,但没有一个真正帮助我解决问题:

iPhone CoreData properties: changes to managedObjects are too slow

ios CoreData: NSFetchedResultsController performances

我有一个包含大约 5,000 行的 tableview,当前由 fetched results controller 管理。

每一行显示文档实体的基本属性,还包括一个按钮,供用户将特定文档标记为收藏夹。诚然,Document 实体与几个不同的实体有关系,并且底层 SQLite 数据库很大(~20mb)。

获取每一行的属性相对较快,并且表格视图在处理这么多项目时表现得非常好。保存更改也不是问题。

当我尝试更改我的 Document 实体的 isFavourite (BOOL) 属性时,我的问题出现了。此属性在按钮修饰内部事件中设置/更新:

[document setIsFavourite:[NSNumber numberWithBool:![document isFavourite]]]

这里的问题是,每次点击收藏按钮时,这行特定的代码都会阻塞 UI 约 1-2 秒,这显然并不理想。

我尝试将 isFavourite 属性标记为索引,并增加了 fetch 批量大小,最后为 NSFetchedResultsController 创建了一个缓存,但似乎对性能没有任何帮助。

我设法避免 UI 锁定的唯一方法是在后台线程上执行属性设置,但这涉及创建新上下文、注册通知以及在保存上下文时合并更改。在这种情况下,会出现另一个问题,因为当我使用合并更改响应保存通知时,我获取的结果控制器似乎很困惑,并且更改的行会自动从我的 tableview 中删除,唯一的方法是做一个 [tableview reloadData]。

有没有其他人遇到过类似的问题,还有什么我可以尝试解决的吗?

非常感谢,

罗格

【问题讨论】:

您如何确认该特定行导致挂起? 仪器是你的朋友。如果那条线真的是违规者,我会使用仪器来查看是什么 kvo 观察者导致你停滞不前。 @ImHuntingWabbits 我试过仪器,但由于某种原因它不允许我在 iOS 上运行任何核心数据模板(它说它不兼容)。有没有其他办法? 您不需要运行任何一个 CoreData 模板,只需使用时间分析器查看 UI 响应点击后导致您速度变慢的原因。 【参考方案1】:

该行不应导致挂起,因为无需获取任何内容。您已经在内存中拥有文档对象,并且您正在更改内存中该对象的单个属性。

我只能想到这样的一行会导致挂起的两个原因。

首先,您有一个setIsFavourite: 的自定义访问器,它会触发驱动故障和获取的副作用。例如。当isFavourite 属性更改触发获取的属性时,您将触发自定义逻辑。

我倾向于这种解释,因为您使用的是旧的参考表格,而不是:

document.isFavourite=[NSNumber numberWithBool:![document isFavourite]];

如果您手动创建了document 对象的类,请检查您是否使用@dynamic 而不是@synthesize 作为属性。后者不适用于 NSManagedObject 子类。

其次,您在触发类似级联的属性上设置了验证,例如验证必须检查另一个对象中的属性。

我很怀疑这行代码实际上是问题的根源。

【讨论】:

经过进一步调查,我认为您可能是对的,这一特定行并不是我问题的真正原因,而是触发它的原因。我相信这个属性值更改会触发获取的结果控制器/tableview 更新方法,在这种情况下这是完全没有必要的,所以我想知道是否有可能以某种方式防止这种情况发生(对于特定属性)?我用一个简单的 fetch 请求做了一个测试,它运行良好(我根据需要手动更新 UI)。 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 中检查您的代码,看看您做出更改后会发生什么。你有自定义访问器吗? 是的,正如预期的那样,当属性更改时会触发开关,但有趣的是,它所做的只是调用configureCell:atIndexPath:,这实际上更新了 UI 以显示该项目已标记为收藏。我不明白为什么要锁定 UI 会是一项如此昂贵的任务? 不应该。这是一项非常常见的任务。答案在代码细节中。您可以使用 Instruments 来分析代码,或者如果您不熟悉工具,只需在可疑方法的开始和结束处记录时间戳。这将确切地告诉您哪种方法令人困惑。然后您可以将其缩小到该行。 再次感谢您的帮助,我会看看我如何去发布我的发现。

以上是关于NSManagedObject 的设置属性阻止了核心数据中的 iPad UI'的主要内容,如果未能解决你的问题,请参考以下文章

在 NSManagedObject 上设置双属性的值

设置 NSManagedObject 的 Bool 属性会引发“iOS 10 中未捕获的异常”

Xcode 中 NSManagedObject 属性的默认值

为关系内部的属性设置值时“无法调用 NSManagedObject 类上的指定初始化程序”(核心数据)

属性作为“当前 NSManagedObject”的视图控制器中的 NSManagedObject

Swift:CoreData NSManagedObject 的自定义设置器