核心数据:子上下文是否为新插入的对象获取永久的objectID?

时间:2012-08-16 15:10:35

标签: ios core-data concurrency nested nsmanagedobjectcontext

我有一个应用程序,其中有两个托管对象上下文设置如下:

  • 父上下文:NSPrivateQueueConcurrencyType,链接到持久存储。
  • 主要上下文:NSMainQueueConcurrencyType,父上下文的子项。

当将新的托管对象插入主上下文时,我保存主上下文,然后保存父上下文,如下所示:

[context performBlockAndWait:^{
    NSError * error = nil;
    if (![context save: &error]) {
        NSLog(@"Core Data save error %@, %@", error, [error userInfo]);
    }
}];

[parentContext performBlock:^{
    NSError *error = nil;
    BOOL result = [parentContext save: &error];
    if ( ! result ) {
        NSLog( @"Core Data save error in parent context %@, %@", error, [error userInfo] );
    }
}];

我的理解是,首次创建管理对象时,它具有临时objectID。然后保存主上下文,并且此对象及其临时ID将转到父上下文。然后保存父上下文。保存最后一个上下文后,父上下文中的临时objectID将转换为永久objectID

所以:

  • 永久对象ID是否会自动返回传播 主要(儿童)背景?
  • 当我强制获取对象永久ID时 [NSManagedObjectContext obtainPermanentIDsForObjects:error:],然后对应用程序进行后台处理,重新激活它,重新加载,使用主要上下文objectWithID:获取对象,并访问属性,我得

      

    “CoreData无法解决......”。

  •   
  这种方法有什么问题?

3 个答案:

答案 0 :(得分:42)

这是一个已知的错误,希望很快得到解决,但一般来说,获取永久ID就足够了,只要您在第一个子项中保存数据之前这样做,并且只包含插入的对象:

[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:&error]

在某些复杂情况下,最好在创建实例后立即获取永久ID,尤其是在您有复杂关系的情况下。

您如何以及何时致电obtainPermanentIDsForObjects

我没有关注应用程序崩溃的部分。也许更好的解释会有所帮助。

答案 1 :(得分:10)

正如Jody所说,当使用子ManagedObjectContext在后台线程中创建新的NSManagedObject时,您必须通过在保存之前执行以下操作来强制创建永久ID:

NSError *error = nil;

[threadedMOC obtainPermanentIDsForObjects:threadedMOC.insertedObjects.allObjects error:&error];

BOOL success = [threadedMOC save:&error];
恕我直言,这样做并不是很直观 - 毕竟,在你保存之前,你要求永久身份证!但这是它似乎工作的方式。如果您在保存后要求提供永久ID,则该ID仍然是临时的。在Apple Docs中,您实际上可以使用以下内容来确定对象的ID是否是临时的:

BOOL isTemporary = [[managedObject objectID] isTemporaryID];

答案 2 :(得分:1)

Swift中的iOS 8.3解决方案仍然存在问题:

func saveContext(context: NSManagedObjectContext?){
   NSOperationQueue.mainQueue().addOperationWithBlock(){
    if let moc = context {
        var error : NSError? = nil
        if !moc.obtainPermanentIDsForObjects(Array(moc.insertedObjects), error: &error){
            println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)")
        }
        if moc.hasChanges && !moc.save(&error){
            println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)")
        }
    }
 }
}

func saveBackgroundContext(){
    saveContext(self.defaultContext)

    privateContext?.performBlock{
        var error : NSError? = nil
        if let context = self.privateContext {

            if context.hasChanges && !context.save(&error){
                println("\(__FUNCTION__)\n \(error?.localizedDescription)\n \(error?.userInfo)")
            }else {
                println("saved private context to disk")
            }
        }
    }
}

其中:

  • defaultContext具有concurrencyType .MainQueueConcurrencyType
  • privateContext具有concurrencyType .PrivateQueueConcurrencyType