将Core Data与服务器响应同步

时间:2014-02-18 22:34:32

标签: ios objective-c core-data afnetworking

我不知道如何处理发生在我身上的问题。

我有一个使用AFNetworking从服务器获取JSON的应用,我使用SQLiteCore Data放入NSArray。但每次我启动一个应用程序时,我必须chceck服务器上是否有一些新对象,并将它们与设备上的本地对象同步。 如何处理服务器和应用之间的同步?

一种方法是清除整个数据库并再次下载所有内容,但我有一个属性保持对象的状态(选择),我不能丢失这些信息。我得到了一个建议,将响应与当前数据库同步,但我真的不知道如何有效地以聪明的方式做到这一点。

我唯一的想法是获取所有内容,并将响应中的每个对象与整个[[AFHTTPRequestOperationManager manager] GET:ALL_GROUPS parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { for (id group in responseObject) { Group *groupEntity = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:self.moc]; groupEntity.name = [group valueForKey:@"name"]; groupEntity.cashID = [group valueForKey:@"id"]; groupEntity.caseInsensitiveName = [[group valueForKey:@"name"] lowercaseString]; groupEntity.selected = FALSE; NSError *error; if (![self.moc save:&error]) { NSLog(@"Couldn't save: %@", [error localizedDescription]); } } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { // Show alert with info about internet connection UIAlertView *internetAlert = [[UIAlertView alloc] initWithTitle:@"Ups!" message:@"Wygląda na to, że nie masz połączenia z internetem" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [internetAlert show]; }]; 进行比较。如果有匹配则断开循环,如果没有添加对象。

我正在使用此方法从服务器获取所有内容并将其放入数据库:

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Group" 
                                              inManagedObjectContext:self.moc];
    [fetchRequest setEntity:entity];
    NSError *error;
    NSArray *fetchedObjects = [self.moc executeFetchRequest:fetchRequest error:&error];

这个小家伙拿走一切:

{{1}}

我很感激任何建议......我坚持这个......

3 个答案:

答案 0 :(得分:1)

虽然@Rich解决方案是正确的,但它是O(N * M)复杂性解决方案 N是数据库中的组总数
M是答复中收到的组数

您的成功代码可能是:

NSMutableDictionary* groups = [NSMutableDictionary new];
NSMutableArray* newIds = [NSMutableArray new];
for (id group in responseObject) {
    Group *groupEntity = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:self.moc];

    groupEntity.name = [group valueForKey:@"name"];
    groupEntity.cashID = [group valueForKey:@"id"];
    groupEntity.caseInsensitiveName = [[group valueForKey:@"name"] lowercaseString];
    groupEntity.selected = NO;
    groups[groupEntity.cashID] = groupEntity;
    [newIds addObject:groupEntity.cashID];
}

NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Group"];
[r setIncludesPendingChanges:NO];
r.predicate = [NSPredicate predicateWithFormat:@"cashID IN %@",newIds];
NSArray *existingGroups = [self.moc executeFetchRequest:r error:&error];

for (Group* g in existingGroups) {
    Group* newGroup = groups[g.cashID];
    g.name = [newGroup valueForKey:@"name"];
    g.cashID = [newGroup valueForKey:@"cashID"];
    g.caseInsensitiveName = [[newGroup valueForKey:@"name"] lowercaseString];
    [self.moc deleteObject:newGroup];
}

// Save any changes
NSError *error;
if (![self.moc save:&error]) {
    NSLog(@"Couldn't save: %@", [error localizedDescription]);
}

哪个是O(M)复杂性

答案 1 :(得分:0)

您在获取当前数据然后与新数据进行比较时处于正确的位置。 最简单的方法是循环内部的循环:

-(void)makeRequest
{
    [[AFHTTPRequestOperationManager manager] GET:ALL_GROUPS parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [self addNewObjects:responseObject];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        // Show alert with info about internet connection
        UIAlertView *internetAlert = [[UIAlertView alloc] initWithTitle:@"Ups!" message:@"Wygląda na to, że nie masz połączenia z internetem" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [internetAlert show];
    }];
}

-(void)addNewObjects:(NSArray *)groups
{
    // Get the current groups
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Group" inManagedObjectContext:self.moc];
    [fetchRequest setEntity:entity];
    NSError *error;
    NSArray *currentGroups = [self.moc executeFetchRequest:fetchRequest error:&error];

    for (id group in groups) {

        id groupID = [group valueForKey:@"id"];

        Group *currentlySavedGroup = nil;

        // Look for a current object
        for (Group *groupEntity in currentGroups) {
            if ([groupEntity.cashID isEqualTo:groupID]) {
                // We've found a current object so finish looking
                currentlySavedGroup = groupEntity;
                break;
            }
        }

        if (!currentlySavedGroup) {
            // Create a new one
            Group *currentlySavedGroup = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:self.moc];
            currentlySavedGroup.selected = NO;
        }

        // Update regardless of saved or not
        currentlySavedGroup.name = [group valueForKey:@"name"];
        currentlySavedGroup.cashID = [group valueForKey:@"id"];
        currentlySavedGroup.caseInsensitiveName = [[group valueForKey:@"name"] lowercaseString];
    }

    // Save any changes
    NSError *error;
    if (![self.moc save:&error]) {
        NSLog(@"Couldn't save: %@", [error localizedDescription]);
    }
}

答案 2 :(得分:0)

如果您的主要目标是减少净传输和更快的同步,我建议您将服务器更改为版本化数据结构,当用户从服务器加载数据时,您首先上传您设备上的版本号,然后服务器将最新版本与设备上的版本进行比较,确定设备上已有的数据是否已更改,设备上缺少哪些数据,仅将这些数据传输到设备,如果大多数数据保持不变,它将使您的同步更快设备和服务器之间相同。