将核心数据与数据库同步 - 更新记录非常慢

时间:2013-07-25 13:04:28

标签: ios objective-c core-data synchronization nsfetchrequest

我正在处理的应用程序必须通过Web服务调用与数据库保持同步。

您最初必须插入大约300,000条记录,这需要花费大量时间。初始下载后,它会调用更新Web服务以获取所有已更改的记录。

在更新调用期间,我必须首先查看该对象是否已存在,这确实会降低该更新过程的速度。通常在早上有大约5k的记录要更新,这几乎与简单地插入300k记录一样长。

代码如下。有更快,更有效的方法吗?

code in loop when iterating through JSON records from server

    if(isUpdating)
    {
        CaseStatusCode *oldObj = [CaseStatusCode doesExist:[record valueForKey:@"JSONData"] uid:[record valueForKey:@"RecordUID"] inContext:temporaryContext];
        if(oldObj) //it exists
        {
            [oldObj initWithJSONSting:[record valueForKey:@"JSONData"]];
        }
        else //create new
        {
            NSEntityDescription *desc = [NSEntityDescription entityForName:NSStringFromClass([CaseStatusCode class]) inManagedObjectContext:temporaryContext];
            CaseStatusCode *worker = [[CaseStatusCode alloc] initWithEntity:desc insertIntoManagedObjectContext:temporaryContext];
            [worker initWithJSONSting:[record valueForKey:@"JSONData"]];
        }
    }

确实存在功能

+ (CaseStatusCode *)doesExist:(NSString *)jsonString uid:(NSString *)uid inContext:(NSManagedObjectContext *)moc
{
    SBJsonParser *parser = [[SBJsonParser alloc] init];
    NSError *e;
    NSDictionary *jsonObj =  [parser objectWithString:jsonString error:&e];

    if(uid || NULL_TO_NIL([jsonObj valueForKey:@"CaseStatusCodeUID"]))
    {
        if(jsonObj)
        {
            uid = [jsonObj valueForKey:@"CaseStatusCodeUID"];
        }
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[self entityName]];
        [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"caseStatusCodeUID ==[cd] %@", uid]];
        [fetchRequest setFetchLimit:1];

        NSError *error = nil;

        if ([moc countForFetchRequest:fetchRequest error:&error] == 0) {
            NSLog(@"!!!WARN: NO Object Matches for pred: %@", fetchRequest.predicate);
            return nil;
        }
        else
        {
            // fetch your object
            CaseStatusCode *result = [[moc executeFetchRequest:fetchRequest error:&error] lastObject];
            if (error != nil) {
                NSLog(@"ERROR: %@ %@", [error localizedDescription], [error userInfo]);
                return nil;
            }
            return result;
        }
    }
    return nil;
}

初始化代码

- (void)initWithJSONSting:(NSString *)jsonString
{
    SBJsonParser *parser = [[SBJsonParser alloc] init];
    NSError *e;
    NSDictionary *jsonObj =  [parser objectWithString:jsonString error:&e];

    if(e)
    {
        NSLog(@"JSON Error Creating State: %@", [e localizedDescription]);
    }
    else
    {
        MySingleton *globals = [MySingleton sharedInstance];
        self.token = globals.token;

        self.CaseStatusCodeUID = NULL_TO_NIL([jsonObj valueForKey:@"CaseStatusCodeUID"]);
        self.CaseStatusCode = NULL_TO_NIL([jsonObj valueForKey:@"CaseStatusCode"]);
        self.Active = NULL_TO_NIL([jsonObj valueForKey:@"Active"]);
        self.desc = NULL_TO_NIL([jsonObj valueForKey:@"Description"]);
        self.BaseStatus = NULL_TO_NIL([jsonObj valueForKey:@"BaseStatus"]);

    }
}

感谢。


EDIT 我试图跟随苹果的例子。我正在构建一个UID的NSArray,然后使用IN谓词构建一个获取请求。我得到0结果,并且我验证了具有该UID的那种类型的对象。

uidArray = (NSMutableArray *)[uidArray sortedArrayUsingSelector:@selector(compare:)];
viewName = @"CaseStatusCode";
uidKey = @"caseStatusCodeUID";

// create the fetch request to get all CaseStatusCode matching the IDs
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:viewName inManagedObjectContext:temporaryContext]];
[fetchRequest setPredicate: [NSPredicate predicateWithFormat: @"%@ IN %@",uidKey, uidArray]];

// Make sure the results are sorted as well.
[fetchRequest setSortDescriptors:@[ [[NSSortDescriptor alloc] initWithKey:uidKey ascending:YES] ]];
// Execute the fetch.
NSError *error;
NSArray *matchingObjectsArray = [temporaryContext executeFetchRequest:fetchRequest error:&error];
NSLog(@"fetchRequest: %@", fetchRequest.description);
NSLog(@"# RECORDS TO UPDATE: %d",matchingObjectsArray.count );

下面是生成的FetchRequest:

<NSFetchRequest: 0x1f5d69d0> (entity: CaseStatusCode; predicate: ("caseStatusCodeUID" IN {"ef236614-aaa2-49ae-8713-fd4847948498"}); sortDescriptors: ((
    "(caseStatusCodeUID, ascending, compare:)"
)); type: NSManagedObjectResultType; )

就像我说的那样,带有该UID的caseStatusCode确实存在。另外,如果我没有设置谓词,我会得到所有的CaseStatusCodes,所以我知道fetch正在运行..谓词只有一些。

编辑#2

好的,我上面是愚蠢的,正确的谓词格式使用%K:

[fetchRequest setPredicate: [NSPredicate predicateWithFormat: @"%K IN %@",uidKey, uidArray]];

编辑#3

迭代idArray和resultsArray的最佳方法是什么?即

  

最终得到两个已排序的数组 - 一个传递了员工ID   到获取请求,以及与匹配的托管对象之一   他们。要处理它们,您可以按照这些列表查看已排序的列表   步骤进行:

     
      
  1. 获取下一个ID和员工。如果ID与员工ID不匹配,   为该ID创建一个新的Employee。
  2.   
  3. 获取下一位员工:如果是ID   匹配,移动到下一个ID和员工。
  4.   

2 个答案:

答案 0 :(得分:2)

我建议您阅读此Implementing Find-or-Create Efficiently声音,看看这是您正在使用的区域。

答案 1 :(得分:1)

考虑循环遍历所有JSON对象以收集所有CaseStatusCodeUID,然后在单个获取请求中获取它们。

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"caseStatusCodeUID IN[cd] %@", uidArray]];

然后遍历结果。

相关问题