2013-07-14 47 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