在iOS 5中使用UIManagedDocument和父/子上下文导入核心数据后台

时间:2012-04-07 20:16:48

标签: core-data ios5 nsmanagedobject nsmanagedobjectcontext uimanageddocument

我在iOS 5中有一个目录应用程序,它从XML下载数据并使用带有UITableView的表视图控制器在NSFetchedResultsController中显示它们。数据存储在核心数据UIManagedDocument中。因为我不想在下载和导入数据时阻止主队列,所以我创建了一个用于下载数据的后台队列和一个带有NSManagedObjectContext的新子NSPrivateQueueConcurrencyType,用于导入document.managedObjectContext的数据作为父母。当我完成导入数据时,I -save:在子上下文中发生更改,并且更改将传播到父上下文。浏览目录时,我会在需要时导入其他数据。一切正常,直到UIManagedDocument自动保存。

我已使用-com.apple.CoreData.SQLDebug 1打开核心数据SQL调试,以查看文档何时自动保存。

document.managedObjectContext中创建具有重复ID的文档的自动保存对象后(我的所有实体id数据库都有唯一的id参数)。

我做错了什么?


我创建了一个简单的示例代码来重现问题 以下是代码:http://dl.dropbox.com/u/20987346/ViewController.m
这是完整的Xcode项目:http://dl.dropbox.com/u/20987346/CoreDataTest.zip

以下是在后台进行导入的方法。

- (void)backgroundImport
{
    static int counter;

    NSManagedObjectContext *backgroundContext;
    backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    backgroundContext.parentContext = self.document.managedObjectContext;

    [backgroundContext performBlock:^{
        NSManagedObject *entity;

        for (int i = 0; i < 2; i++) {
            entity = [self entityWithID:[NSNumber numberWithInt:arc4random() % 20 + 1]
                 inManagedObjectContext:backgroundContext];
            [entity setValue:[NSString stringWithFormat:@"A Name %d", ++counter] forKey:@"name"];
        }

        [self dumpEntitiesInManagedObjectContext:backgroundContext];

        NSError *error;
        [backgroundContext save:&error];
        if (error) NSLog(@"%@ (%@)", [error localizedDescription], [error localizedFailureReason]);

        [backgroundContext.parentContext performBlock:^{
            [self dumpEntitiesInManagedObjectContext:backgroundContext.parentContext];
        }];
    }];
}

该方法导入两个实体。 -entityWithID:获取具有指定ID属性的实体,如果它不存在,则使用NSEntityDescription -insertNewObjectForEntityForName:创建一个实体。 -dumpEntitiesInManagedObjectContext:转储所有要记录的实体(一次在导入上下文中,一次在文档的上下文中)。

问题是当文档自动保存并进行了一些额外的导入时,我在日志中得到以下内容:

[1140b] Entities: 10             [fb03] Entities: 11
[1140b]   2: A Name 1            [fb03]   2: A Name 1
[1140b]   3: A Name 4            [fb03]   3: A Name 4
[1140b]   4: A Name 8            [fb03]   4: A Name 8
[1140b]   5: A Name 12           [fb03]   5: A Name 12
[1140b]   6: A Name 10           [fb03]   6: A Name 10
[1140b]   8: A Name 6            [fb03]   8: A Name 6
[1140b] **12: A Name 11**        [fb03] **12: A Name 11**
[1140b]   13: A Name 9           [fb03] **12: A Name 5**
[1140b]   17: A Name 3           [fb03]   13: A Name 9
[1140b]   18: A Name 2           [fb03]   17: A Name 3
                                 [fb03]   18: A Name 2

导入上下文有10个实体,但主上下文有11个实体,ID为12的实体是重复的。似乎旧对象尚未在父上下文中修改,而是添加。

2 个答案:

答案 0 :(得分:3)

我仍然处于所有这些事情(Core Data和UIManagedDocument一起工作)中,但我认为这个问题可能会解决您的情况:Core Data managed object does not see related objects until restart Simulator

它涉及在“正常”流程之前强制临时ID永久使用: [context obtainPermanentIDsForObjects:[inserts allObjects] error:&error]

答案 1 :(得分:1)

我遇到了这个问题并在NSEntityDescription上做了一个小类来解决问题:

@implementation NSEntityDescription (PermanentID)
+ (id)insertNewPermanentObjectForEntityForName:(NSString *)entityName
                        inManagedObjectContext:(NSManagedObjectContext *)context
{
    id object = [self insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
    NSError *error;
    if (![context obtainPermanentIDsForObjects:[NSArray arrayWithObject:object] error:&error]) {
        NSLog(@"Permanent ID not given");
    }
    if (error) {
        NSLog(@"%@", error);
    }
    return object;
}

还有更多关于it here on my site的内容,但我已在此处重现了此类别,因此您无需点击即可。