Iphone 核心数据模式:如何根据网络的变化高效地更新本地信息?

Iphone 核心数据模式:如何根据网络的变化高效地更新本地信息?,iphone,performance,core-data,cocoa-design-patterns,nsfetchrequest,Iphone,Performance,Core Data,Cocoa Design Patterns,Nsfetchrequest,我的应用程序中存在一些效率低下的问题,我希望能够理解并解决这些问题 我的算法是: fetch object collection from network for each object: if (corresponding locally stored object not found): -- A create object if (a nested related object locally not found): -- B create a relate

我的应用程序中存在一些效率低下的问题,我希望能够理解并解决这些问题

我的算法是:

fetch object collection from network
for each object:
  if (corresponding locally stored object not found): -- A
    create object
    if (a nested related object locally not found): -- B
      create a related object
我在第A行和第B行上进行检查,方法是创建一个谓词查询,该查询具有作为模式一部分的相关对象的键。我看到A(始终)和B(如果执行分支到该部分)都会生成一个SQL select,如下所示:

2010-02-05 01:57:51.092 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE1 t0 WHERE  t0.ZID = ? 
2010-02-05 01:57:51.097 app[393:207] CoreData: annotation: sql connection fetch time: 0.0046s
2010-02-05 01:57:51.100 app[393:207] CoreData: annotation: total fetch execution time: 0.0074s for 0 rows.
2010-02-05 01:57:51.125 app[393:207] CoreData: sql: SELECT <a bunch of fields> FROM ZTABLE2 t0 WHERE  t0.ZID = ? 
2010-02-05 01:57:51.129 app[393:207] CoreData: annotation: sql connection fetch time: 0.0040s
2010-02-05 01:57:51.132 app[393:207] CoreData: annotation: total fetch execution time: 0.0071s for 0 rows.
我觉得这是错误的,我应该以其他方式进行检查。它应该只命中数据库一次,然后从内存中取出,对吗?(即使我知道对象确实存在于本地,并且应该在以前的查询中加载到内存中,SQL也会执行。)但是,如果我只有来自外部源的myObjectId,这是我能想到的最好的方法

所以,也许问题是:如果我有myObjectId(MyObject上的核心数据int64属性),我应该如何正确地检查相关的本地对象是否存在于CD存储中?预加载整个可能的匹配集,然后谓词本地数组


(一种可能的解决方案是将其移动到后台线程。这很好,但当我从线程获取更改并执行[moc mergeChangesFromContextDidSaveNotification:aNotification];(通过通知的方式从后台线程获取更改的对象)时,这仍然会阻塞。)

你或许可以从电子邮件客户端吸取教训

它们的工作方式是首先查询服务器上的消息ID列表。一旦客户机有了这个列表,它就会与它的本地数据存储进行比较,看看是否有什么不同

如果存在差异,则需要采取两种措施中的一种。 1.如果它存在于客户机上,但不存在于服务器上,并且我们是IMAP,则在本地删除。 2.如果它存在于服务器上,但不存在于客户端,则下载消息的其余部分

在您的情况下,首先查询所有ID。然后发送一个后续查询,获取您尚未拥有的数据的所有数据


如果您的记录可能存在于本地,但可能自上次在服务器上下载后已更新,然后,您的查询应该包括上次更新的日期。

听起来您需要的是一组NSManagedObjects,它加载到内存中或存储在比持久对象存储更快访问的地方

这样,您就可以将网络中的对象ID与缓存中的对象ID进行比较,而无需对大型数据集执行获取请求


可能从托管实体类中的-awakeFromInsert中将ID添加到缓存中?

您应该对所有对象执行一次获取,但只获取对象的服务器ID

与设置为
的NSDictionaryResultType一起使用

阅读核心数据编程指南中的“高效实现查找或创建”

基本上,您需要创建一个ID或属性数组,如名称或托管对象实体中的任何内容

然后,您需要创建一个谓词,该谓词将使用此数组过滤托管对象

[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(objectID IN %@)", objectIDs]];
当然,“objectid”可以是任何你可以用来识别的东西。它不必是NSManagedObjectID


然后,您可以执行一个获取请求,并迭代得到的获取对象,以找到重复的对象。如果它不存在,请添加一个新的。

在与同一问题争论了很久之后,我终于偶然发现了这篇博客文章,它完全解决了这个问题(并且是一个可重用的代码块作为奖励!)


而代码示例不包括网络部分;您只需将其加载到NSDictionary中。然后处理本地核心数据上下文的同步。

不是答案,而是“高效导入数据”文档的更新URL


查询服务器对我来说很便宜,而且是异步完成的。我的问题是“查询所有本地id”部分效率低下,并且/或者我无法确定如何正确执行。来自网络的对象具有与NSManagedObjectID无关的不同NSNumber“id”。这就是我在示例中使用的属性。所以,仅仅NSManagedObjectID-s的NSSet是不够的,因为我没有“external ID->managedId”映射?我已经在上阅读了《核心数据编程指南》,但我不记得有任何关于查找或创建的内容。以下是我将此链接标记为答案的链接,因为它与其他几个链接(缓存相关标识符属性)具有相同的意见,但具有链接到官方文档的附加功能。查找或创建正是本文的主题至于我自己,由于我的数据很小,我最终只是将整个对象集提取到内存中,因为数据足够小,我最终需要访问它,这种缓存方式非常快。
[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(objectID IN %@)", objectIDs]];