1

应用程序必须在后台每 10 秒循环更新来自 WebService 的数据,并在主线程中根据用户的请求向用户显示数据。我还需要根据用户请求更新和删除记录。使用 runloop 完成更新。

我已经在 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?

}

我有 Storage 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];
}
}];

请问有什么建议吗?

4

1 回答 1

0

问题可能在操作队列中。您还没有将其最大并发操作数配置为 1,对吧?在这种情况下,它不是串行的,并且您添加到它的操作同时运行。所以这里会发生什么。第一个操作获取具有某个 ID 的对象的计数,没有找到它并创建一个。在保存之前的某个时间点,添加了另一个操作。第二个操作获取具有相同 ID 的对象,没有找到它并创建一个。然后第一个操作保存,然后第二个操作保存,并且您有一个副本。

所以尽量让你的操作队列串行[operationQueue maxConcurrentOperationCount:1];

不,您不必在调用托管对象上下文的合并方法后保存。

于 2013-07-14T19:14:10.860 回答