核心数据模式:如何有效地更新本地信息与网络的变化? [英] Core Data pattern: how to efficiently update local info with changes from network?

查看:158
本文介绍了核心数据模式:如何有效地更新本地信息与网络的变化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程式有一些低效率,我想了解并修正。



我的演算法是:

 每个对象从网络
获取对象集合:
if(对应的本地存储的对象未找到): - A
create object
if(在本地未找到嵌套的相关对象): - B
创建相关对象


$ b b

我通过使用作为模式一部分的相关对象的键来创建谓词查询,从而对A和B行进行检查。我看到A(总是)和B(如果执行分支到那部分)生成一个SQL选择如:

  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:注释:sql连接fetch时间:0.0046s
2010-02-05 01:57:51.100 app [393:207 ] CoreData:annotation:total fetch执行时间:0.0074s为0行。
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:注释:sql连接fetch时间:0.0040s
2010-02-05 01:57:51.132 app [393:207 ] CoreData:annotation:total fetch执行时间:0.0071s为0行。

0.0071s在3GS设备上查询正常,但如果您添加100个,



在我的代码中,我正在使用助手来执行这些抓取:

   - (MyObject *)myObjectById:(NSNumber *)myObjectId {
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[self objectEntity]]; //我的实体缓存
[fetchRequest setPredicate:[self objectPredicateById:objectId]]; //谓词缓存
NSError * error = nil;
NSArray * fetchedObjects = [moc executeFetchRequest:fetchRequest error:& error];
if([fetchedObjects count] == 1){
[fetchRequest release];
return [fetchedObjects objectAtIndex:0];
}
[fetchRequest release];
return nil;
}

MyObject * obj = [self myObjectById];
if(!obj){
// [NSEntityDescription insertNewObjectForEntityForName:... etc
}

我觉得这是错误的,我应该做一些其他的方式。它应该只打一次数据库,然后应该从内存中,对吗? (即使对于我知道的对象肯定存在于本地,应该已经加载到内存与以前的查询SQL)。但是,如果我只有myObjectId从外部源,这是我能想到的最好的。 p>

所以,也许问题是:如果我有myObjectId(MyObject上的Core Data int64属性),我应如何正确检查相关的本地对象是否存在于CD存储?预加载整个可能的匹配,然后断言一个局部数组?



(一个可能的解决方案是将其移动到后台线程,这将是很好的,从该线程获取更改并做[moc mergeChangesFromContextDidSaveNotification:aNotification];(通过通知从后台线程获取更改的对象,这仍然会阻止。)

解决方案

阅读在核心数据编程指南中实现查找或高效实现。



基本上,您需要创建一个ID或属性



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

  [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@(objectID IN%@),objectIDs]]; 

当然,objectIDs可以是你可以用来识别的任何东西。它不一定是NSManagedObjectID。



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


I have some inefficiency in my app that I'd like to understand and fix.

My algorithm is:

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

I am doing the checking on lines A and B by creating a predicate query with the relevant object's key that's part of my schema. I see that both A (always) and B (if execution branched into that part) generate a SQL select like:

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.

0.0071s for a query is fine on a 3GS device, but if you add 100 of these up, you just got a 700ms blocker.

In my code, I'm using a helper to do these fetches:

- (MyObject *) myObjectById:(NSNumber *)myObjectId {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[self objectEntity]]; // my entity cache    
    [fetchRequest setPredicate:[self objectPredicateById:objectId]]; // predicate cache    
    NSError *error = nil;
    NSArray *fetchedObjects = [moc executeFetchRequest:fetchRequest error:&error];
    if ([fetchedObjects count] == 1) {
        [fetchRequest release];
        return [fetchedObjects objectAtIndex:0];
    }
    [fetchRequest release];
    return nil;
}

MyObject *obj = [self myObjectById];
if (!obj) {
   // [NSEntityDescription insertNewObjectForEntityForName: ... etc
}

I feel this is wrong and I should do the check some other way. It should only hit the database once and should come from memory thereafter, right? (The SQL gets executed even for objects that I know for sure exist locally and should have been loaded to memory with previous queries.) But, if I only have myObjectId from an external source, this is the best I could think of.

So, perhaps the question is: if I have myObjectId (a Core Data int64 property on MyObject), how should I correctly check if the relevant local object exists in CD store or not? Preload the whole set of possible matches and then predicate a local array?

(One possible solution is moving this to a background thread. This would be fine, except that when I get the changes from the thread and do [moc mergeChangesFromContextDidSaveNotification:aNotification]; (getting changed objects from background thread by way of notification), this still blocks.)

解决方案

Read "Implementing Find-or-Create Efficiently" in Core Data Programming Guide.

Basically you need to create an array of IDs or properties like names, or anything you have from the managed object entity.

Then you need to create a predicate that will filter the managed objects using this array.

[fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(objectID IN %@)", objectIDs]];

Of course "objectIDs" could be anything that you can use to identify. It doesn't have to be the NSManagedObjectID.

Then you could do one fetch request, and iterate the resulting fetched objects, to find duplicates. Add a new one if it doesn't exist.

这篇关于核心数据模式:如何有效地更新本地信息与网络的变化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆