【问题标题】:Why does NSArrayController fetches twice in a row?为什么 NSArrayController 连续获取两次?
【发布时间】:2016-04-10 13:10:46
【问题描述】:

我在使用 Core Data 和 NSArrayController 的 OS X 应用程序中遇到了一些奇怪的行为。每个 fetch: 发送到数组控制器的消息都会导致从持久性存储 (sqlite) 进行 两次 fetch,当然,这会花费两倍的时间来进行 fetch。

当我设置数组控制器的 fetchPredicate 属性然后发送一个 fetch: 消息时会发生这种情况。

我使用标准的苹果核心数据应用程序模板创建了一个简单的测试应用程序,其中一个实体“SomeEntity”只有一个属性“stringAttribute”。我继承了 NSArrayController 并覆盖了 fetchWithRequest:merge:error: 以设置断点并查看数组控制器何时从存储中获取。

然后,我编写了一个仅包含两行的简单操作方法(连接到按钮):

self.arrayController.fetchPredicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];
[self.arrayController fetch:self];

而且,每次我按下按钮时,fetchWithRequest:merge:error: 方法都会被调用两次,导致两次访问持久性存储。

NSArrayController 继承自实现 fetch: 方法的 NSObjectController。文档说

从 OS X v10.4 开始,此方法的结果将延迟到 runloop 的下一次迭代,以便错误呈现机制可以以表格形式提供反馈。

fetchWithRequest:merge:error: 确实由运行循环机制中触发的 NSInvocation 调用。经过一点断点设置后,我发现一个 NSInvocation 是由

行创建的
self.arrayController.fetchPredicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];

下一行还有第二个

[self.arrayController fetch:self];

当我注释掉第二行时,控制器根本不会获取。因此,只要我想在获取之前设置获取谓词,我就会得到两次获取。奇怪的是,当我在应用启动后第一次按下按钮时不会发生这种情况。

这感觉很奇怪,因为我基本上只在标准 Core Data 堆栈中添加了两行代码。当我用测试数据填充存储并测量 fetchWithRequest:merge:error: 完成所需的时间时,我可以清楚地看到 fetch 发生两次并花费两倍时间的性能问题。

直接调用 fetchWithRequest:merge:error: 不是一个理想的解决方案,因为 NSArrayController 中有一些自动功能,我必须自己重新实现。不应该是首先设置 fetchPredicate 而不是简单地调用 fetch: 的正确方法吗?

有什么想法吗?

【问题讨论】:

  • arrayController.automaticallyPreparesContent 开启了吗?
  • 不,不是,而是有趣的问题。当我打开它时,它会在 XIB 加载后立即获取两次!所以我们看到 fetchWithRequest:merge:error: 调用了两次(并且花费了两倍的时间),即使我们根本不编写任何代码!

标签: objective-c macos core-data


【解决方案1】:

显然NSArrayController 试图变得聪明并自动获取setFetchPredicate:(如果之前已获取)。

【讨论】:

  • 不,当我设置谓词时它不会获取。这就是让它如此奇怪的原因。除非我调用 fetch:,否则它不会获取。它要么获取两次,要么根本不获取。
  • 您必须至少拨打一次fetch: 或打开automaticallyPreparesContent。如果NSArrayController 从未获取过,则不会在setFetchPredicate: 中获取。如果NSArrayController 在调用setFetchPredicate: 之前已获取,它确实会获取setFetchPredicate:。
  • 啊,谢谢,现在我明白是怎么回事了。但我必须说,如果 NSArrayController 能更智能并且避免在运行循环中将这些双重获取排入队列,那就太好了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-16
  • 2020-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多