iOS 5核心数据与多个NSManagedObjectContext重复行

时间:2013-01-30 19:58:35

标签: ios core-data nsfetchedresultscontroller nsmanagedobjectcontext

我们的表视图控制器使用NSFetchedResultsController来显示Core Data中的数据。我们在后台下载新数据。当在新数据中修改实体时,在iOS 5.1.1手机上,我们看到将其视为表中的新行而不是更新。无法在iOS 5.1模拟器或iOS 6设备上复制。

UIApplicationDelegate创建一个并发类型为NSManagedObjectContext的{​​{1}}。我们的NSMainQueueConcurrencyType实施UITableViewController。在NSFetchedResultsControllerDelegate中,我们将获取新数据。在获取数据的方法中,我们使用并发类型viewWillAppear创建第二个NSManagedObjectContext。我们在新的上下文上做NSPrivateQueueConcurrencyType,并进行网络调用和json解析。有performBlock来获取以前的数据,因此我们可以删除旧对象,或修改具有相同ID的任何现有实体。在修改现有实体或创建新实体之后,我们然后NSFetchRequest旧实体对象。然后我们保存这个私有上下文。然后在父上下文中,执行deleteObject以保存更改。

在iOS5.1上,表格不正确。如果我们更改对象而不是修改它,它将作为新行添加到表中。如果我们离开这个控制器并返回它,获取新数据,它会显示正确的数量。

AppDelegate.m

performBlock

从服务器获取的类

- (void)saveContext
{

    [self.privateWriterContext performBlock:^{
        NSError *error = nil;
        [self.privateWriterContext save:&error];
        // Handle error...
        [[NSNotificationCenter defaultCenter] removeObserver:self     name:NSManagedObjectContextDidSaveNotification object:self.privateWriterContext];
    }];
}

#pragma mark - Core Data stack

- (NSManagedObjectContext *)privateWriterContext
{
    if (__privateWriterContext != nil) {
        return __privateWriterContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        __privateWriterContext = [[NSManagedObjectContext alloc]     initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [__privateWriterContext setPersistentStoreCoordinator:coordinator];
    }
    return __privateWriterContext;
}

- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil) {
        return __managedObjectContext;
    }

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        __managedObjectContext = [[NSManagedObjectContext alloc]     initWithConcurrencyType:NSMainQueueConcurrencyType];
        [__managedObjectContext setParentContext:self.privateWriterContext];
    }

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(saveContext:)
                                                      name:NSManagedObjectContextDidSaveNotification
                                               object:__managedObjectContext];
    return __managedObjectContext;
}

2 个答案:

答案 0 :(得分:1)

我最近也遇到了这个问题。

问题是由于不同线程中的两个上下文。

在运行iOS 5.1的设备上,合并它们会导致它插入新记录而不是更新它。我将后台线程更改为使用主上下文,问题就消失了。

不知道为什么合并在这种特殊情况下不起作用。

答案 1 :(得分:0)

我有样品问题。原因是awakeFromInsert的实现。当主队列上下文意外地合并私有队列时,将调用该方法。

我的代码就是这样。

public override func awakeFromInsert() {
    super.awakeFromInsert()

    let context = self.managedObjectContext!

    let tag1 = NSEntityDescription.insertNewObjectForEntityForName("Tag", inManagedObjectContext: context) as! TagMO
    tag1.name = "Dog"

    let tag2 = NSEntityDescription.insertNewObjectForEntityForName("Tag", inManagedObjectContext: context) as! TagMO
    tag2.name = "Cat"

    tags = NSSet(array: [tag1, tag2])
}

在这种情况下,当从私有上下文合并到主队列上下文时,标记对象将是4而不是2。