2013-07-14 46 views
1

應用程序必須在後臺每10秒更新WebService中的數據,並通過主線程中的請求將數據顯示給用戶。另外我需要根據用戶請求更新和刪除記錄。 使用runloop完成更新。IOS如何同步多線程NSManagedObjectContext?

我已經註冊通知,並在AppDelegate中

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil]; 

- (void)contextChanged:(NSNotification*)notification 
{ 
    if ([notification object] == [self managedObjectContext]) return; 

    if (![NSThread isMainThread]) { 
     [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES]; 
     return; 
    } 

    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification]; 
    [self saveContext]; //do I need this here or marge save data too? 

} 

我有存儲sharedInstance類

NSOperationQueue* operationQueue; 

然後插入,更新,選擇運營商從任何線程加入這樣:

-(void)do_something 
{ 
    [self.operationQueue addOperationWithBlock:^{ 
    NSManagedObjectContext*moc; //creating new NSManagedObjectContext with AppDelegate.persistentStoreCoordinator 
    //do my staff 
    [moc save:&error] 
    }] 
} 

問題是,當我嘗試使用@「my_id =%@」更新實體時,@(my_id)

[moc countForFetchRequest:fetchRequest error:&error] 

返回0並導致重複的插入存在實體 問題是與同步。 請諮詢。我應該使用dispatch_queue_create(「com.my。」,0)的實例嗎?而不是每個CoreData操作?


我也嘗試刪除operationQuiue

-(void)query:(void(^)(NSManagedObjectContext *context))queryBlock 
{ 
    NSLog(@"query CALL"); 
    __block NSManagedObjectContext *context; 
    //if remove dispatch_sync and/or run in main thread result the same 
    dispatch_sync(dispatch_queue_create("com.myapp.db-queue", 0), ^{ 
    AppDelegate*app = AppDelegate(); 

    //same result if I use 
    //app.persistentStoreCoordinator or 
    //[app.managedObjectContext persistentStoreCoordinator] 

    NSPersistentStoreCoordinator *persistentStoreCoordinator= [app.managedObjectContext persistentStoreCoordinator]; 

    context = [NSManagedObjectContext new]; 
    [context setPersistentStoreCoordinator:persistentStoreCoordinator]; 
    [context setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 

    queryBlock(context); 
    if ([context hasChanges]) 
    { 
     NSError*err; 
     [context save:&err]; 
     if (err) { 
      NSLog(@"context save: %@",[err localizedDescription]); 
     } 
    } 
    }); 
} 

,並稱呼其爲:

CoreStorage* cs = [CoreStorage sharedInstance]; 
NSArray* list = [ws GetSections]; //array of NSDictionaries 

//if add this to operationQuiue resunt the same 
[cs query:^(NSManagedObjectContext *moc) { 
NSLog(@"START"); 
for (NSDictionary *section in list) { 

    NSNumber* Id= @([[section objectForKey:@"section_id"] integerValue]); 

    NSFetchRequest * fetchRequest = [NSFetchRequest new]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Section" inManagedObjectContext: moc]; 
    [fetchRequest setEntity:entity]; 
    [fetchRequest setFetchLimit:1]; 
    [fetchRequest setIncludesSubentities:NO]; 
    [fetchRequest setPredicate: [NSPredicate predicateWithFormat:@"section_id=%@",Id]]; 

    NSError *error =nil; 
    Section *entry; 
    if ([moc countForFetchRequest:fetchRequest error:&error] >0) 
    { 
     entry = [moc executeFetchRequest:fetchRequest error:nil][0]; 
     NSLog(@"exist"); //this never call 
    } 
    else 
    { 
     entry = [NSEntityDescription insertNewObjectForEntityForName:@"Section" inManagedObjectContext:moc]; 
     NSLog(@"NEW"); 
    } 

    entry.section_id = Id; 
    entry.timeStamp = [NSDate date]; 
} 
}]; 

任何sugastions好嗎?

+0

我在AppDelegate中 –

回答

0

的問題可能是在操作隊列。您沒有將最大併發操作配置爲1,對嗎?在這種情況下,它不是串行的,並且添加到它的操作併發運行。所以這裏發生了什麼。第一次操作獲取具有某個ID的對象的計數,但沒有找到它並創建一個。在保存之前的某個時間點,添加另一個操作。這第二個操作獲取具有相同ID的對象,但沒有找到它並創建一個。然後第一個操作保存,然後第二個保存,並且你有一個副本。

所以儘量讓你的操作隊列串行[operationQueue maxConcurrentOperationCount:1];

不,你不必調用合併管理對象上下文的方法之後進行保存。

+0

使用NSMergeByPropertyStoreTrumpMergePolicy用於在的NSManagedObjectContext背景和NSMergeByPropertyObjectTrumpMergePolicy對於主線程[operationQueue maxConcurrentOperationCount:1]; - 我做到了。 –

+0

它看起來像NSFetchRequest的設置沒有看到數據庫中的數據。我猜在MOC的問題。 –

+0

訪存請求應始終在商店中查看最新數據。 – eofster