2013-07-14 4 views
1

Приложение должно обновлять данные из WebService в цикле каждые 10 секунд в фоновом режиме и отображать данные пользователю по его запросу в основном потоке. Также мне нужно обновить и удалить записи по запросу пользователя. Обновления выполнены с помощью 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

Я использую NSMergeByPropertyStoreTrumpMergePolicy для NSManagedObjectContext в фоновом режиме и NSMergeByPropertyObjectTrumpMergePolicy для основного потока в AppDelegate –

ответ

0

Проблема, вероятно, в рабочей очереди. Вы не настроили его с максимальными одновременными операциями 1, правильно? В этом случае он не является серийным, и операции, которые вы добавляете к нему, выполняются одновременно. Так вот что происходит. Первая операция выбирает для подсчета объекта с некоторым ID, не находит его и не создает. В какой-то момент до его сохранения добавляется другая операция. Эта вторая операция выбирает объект с тем же идентификатором, не находит его и не создает. Затем первая операция сохраняется, затем вторая сохраняет, и у вас есть дубликат.

Так что постарайтесь сделать вашу очередь операций серийной [operationQueue maxConcurrentOperationCount:1];.

И нет, вам не нужно сохранять после вызова метода слияния контекста управляемого объекта.

+0

[operationQueue maxConcurrentOperationCount: 1]; - Я сделал это. –

+0

Похоже, NSFetchRequest с настройками не видит данные в БД. Я думаю, проблема в MOC. –

+0

Запрос на выборку должен всегда видеть последние данные в магазине. – eofster

Смежные вопросы