2014-02-18 74 views
0

我不知道如何處理髮生在我身上的問題。將核心數據與服務器響應同步

我有一個應用程序正在使用AFNetworking從服務器獲得JSON,我使用Core Data將其放入SQLite。但每次啓動應用程序時,如果服務器上存在一些新對象並與設備上的本地對象同步,則必須進行chceck操作。 如何處理服務器和應用程序之間的這種同步?

的方法之一是再次明確整個數據庫和下載的一切,但我有一個屬性,其持有的對象(選擇)的狀態,我不能失去這個信息。我得到了一個建議,將響應與當前的數據庫同步,但我真的不知道如何有效且智能地​​實現這一點。

我唯一的想法是獲取所有內容,並將每個對象從響應中與整個NSArray進行比較。如果匹配,則循環中斷,如果沒有添加對象。

我用這種方法得到的一切,從服務器,並把它放到數據庫:

[[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]; 

我將不勝感激任何建議.. 。我堅持使用這一個...

+0

用戶可以更改下載到設備的數據嗎? – CarmeloS

+0

@CarmeloS,只有'selected'屬性可以。 – cojoj

+0

由AFHTTPNetworking實現的NSIncrementalStore,你也可以看看它:https://github.com/AFNetworking/AFIncrementalStore –

回答

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)的複雜性

+0

是的,我只是給他一個想法繼續! 雖然你不需要一個數組來存儲'newIds'和一個字典來存儲新的組,你可以使用字典中的'allKeys'方法。 但更重要的是,你的謂詞是錯誤的,它需要'cashID IN%@':) – Rich

+0

@很好,謝謝,我修正了謂詞。該數組在那裏以避免再次通過對象(另一個O(M)操作) –

+0

@DanShelly我的代碼有一個問題。當我第一次運行它時,它沒有保存任何東西......可能'newGroup'應該被聲明爲'Group *'。 – cojoj

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]); 
    } 
} 
+0

我測試過你的解決方案,並且它一遍又一遍地增加了一切... – cojoj

0

如果你的主要目標是減少網絡傳輸和更快的同步,我建議你的服務器更改爲一個版本的數據結構,當從服務器上的用戶負載數據,你首先要上傳你擁有的版本號Ø然後服務器將最新版本與設備上的版本進行比較,確定設備上已有的數據已更改,設備上缺少哪些數據,只將這些數據傳輸到設備,這將使您的同步更快如果大多數數據在設備和服務器之間保持不變。