Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 父/子NSManagedObjectContext的正确实现_Ios_Objective C_Cocoa_Core Data_Nsmanagedobjectcontext - Fatal编程技术网

Ios 父/子NSManagedObjectContext的正确实现

Ios 父/子NSManagedObjectContext的正确实现,ios,objective-c,cocoa,core-data,nsmanagedobjectcontext,Ios,Objective C,Cocoa,Core Data,Nsmanagedobjectcontext,我的应用程序有时会将不一定要保存的对象插入到托管对象上下文中。例如,当我启动“添加实体”模式时,我创建一个托管对象并将其分配给该模式。如果用户从该模式保存,则我保存上下文。如果他取消,我将删除该对象,无需保存 我现在引入了一个“导入”功能,可以切换到我的应用程序(使用URL方案)并添加一个实体。因为其中一个模态可能是打开的,所以此时保存上下文是不安全的。即使用户取消,为模式创建的临时对象也将被保存,并且不能保证删除(从取消操作)将在以后保存-用户可能会退出应用程序 同样,我不能在我的应用程序退出

我的应用程序有时会将不一定要保存的对象插入到托管对象上下文中。例如,当我启动“添加实体”模式时,我创建一个托管对象并将其分配给该模式。如果用户从该模式保存,则我保存上下文。如果他取消,我将删除该对象,无需保存

我现在引入了一个“导入”功能,可以切换到我的应用程序(使用URL方案)并添加一个实体。因为其中一个模态可能是打开的,所以此时保存上下文是不安全的。即使用户取消,为模式创建的临时对象也将被保存,并且不能保证删除(从取消操作)将在以后保存-用户可能会退出应用程序

同样,我不能在我的应用程序退出时简单地保存。如果模态在该点打开,则临时对象将被错误保存

为了解决这个问题,我尝试使用一个子上下文,正如前面所讨论的。在阅读了所有关于SO的资料后,我有几个问题:

  • 我应该为每个上下文使用哪种并发类型?请记住,我这样做不是为了性能/线程好处。我知道如果要有子上下文,我不能将NSConfinementConcurrencyType用于主上下文,但我不确定其他两个选项中哪一个最适合。对于子上下文,它是否需要匹配?或者我可以在这里使用禁闭类型吗?我尝试了各种组合,似乎都可以,但我想知道哪种适合我的要求

  • (附带问题)为什么我只能在使用iVar类的情况下才能实现这一点?我认为我应该能够在创建临时上下文的方法中声明临时上下文,然后稍后使用entity.managedObjectContext引用它。但当我访问它时,它似乎是零?如果我改为使用iVar来保存引用,则会更正此问题

  • 将更改传播到主上下文的正确方式是什么?我已经看到在每个上下文中使用不同的块包装实现的各种注释。它是否取决于我的并发类型?我目前的版本是:

    //save the new entity in the temporary context
    NSError *error = nil;
    if (![myObject.managedObjectContext save:&error]) {NSLog(@"Error - unable to save new object in its (temporary) context");}
    
    //propogate the save to the main context
    [self.mainContext performBlock:^{
        NSError *error2 = nil;
        if (![self.mainContext save:&error2]) {NSLog(@"Error - unable to merge new entity into main context");}
    }];
    
  • 当我的用户保存时,它会向其委托(我的主视图控制器)发送一条消息。委托被传递给已添加的对象,并且它必须在主上下文中找到该对象。但当我在主上下文中查找它时,却没有找到它。主上下文是否包含实体-我可以记录其详细信息并确认它在那里-但地址不同?如果这是要发生的(为什么?),如何在保存后在主上下文中定位添加的对象

  • 谢谢你的洞察力。很抱歉,我提出了一个很长的、由多个部分组成的问题,但我认为以前可能有人已经解决了所有这些问题

  • 如果使用父/子模式,通常使用
    NSMainQueueConcurrencyType
    声明父上下文,使用
    NSPrivateQueueConcurrencyType
    声明子上下文
    NSConfinementConcurrencyType
    用于经典线程模式

  • 如果你想保留上下文,你需要一个强有力的引用

  • 只需在子上下文上调用save方法即可将更改推送到父上下文,如果要持久化数据,还可以在父上下文上调用save。你不需要在一个街区内完成这项工作

  • 有几种方法可以从上下文中获取特定对象。我无法告诉您哪一种方法适用于您的情况,请尝试:

    -objectRegisteredForID:

    -objectWithID:

    -existingObjectWithID:错误:


  • 我也遇到过类似的问题,下面是对你的一些问题的回答- 1.您应该能够使用并发类型
    NSPrivateQueueConcurrencyType
    NSMainQueueConcurrencyType
    2.假设您已经使用父上下文
    mainContext
    创建了一个临时上下文
    tempContext
    (假设为iOS5)。在这种情况下,您只需将托管对象从
    tempContext
    移动到
    mainContext
    -

    object = (Object *)[mainContext objectWithID:object.objectID];
    
    然后可以保存mainContext本身

    也许也

    [childContext reset];
    

    如果您想重置临时上下文。

    父/子MOC模型是核心数据非常强大的功能。它极大地简化了我们过去必须处理的古老的并发问题。然而,正如您所说的,并发性不是您的问题。回答您的问题:

  • 传统上,对于与主线程关联的
    NSManagedObjectContext
    使用
    NSMainQueueConcurrencyType
    ,对于子上下文使用
    NSPrivateQueueConcurrencyType
    s。子上下文不需要与其父上下文匹配。如果不指定类型,则所有
    NSManagedObjectContext
    都会默认使用
    NSConfinementConcurrencyType
    。它基本上是“我将为核心数据管理自己的线程”类型
  • 在没有看到您的代码的情况下,我的假设是您创建子上下文的范围结束并得到清理
  • 使用父/子上下文模式时,需要使用块方法。使用块方法的最大好处是,操作系统将处理将方法调用分派到正确线程的问题。您可以使用
    performBlock
    进行异步执行,也可以使用
    performBlock和wait
    进行同步执行
  • 您可以使用以下方法:

    - (void)saveContexts {
        [childContext performBlock:^{
            NSError *childError = nil;
            if ([childContext save:&childError]) {
                [parentContext performBlock:^{
                    NSError *parentError = nil;
                    if (![parentContext save:&parentError]) {
                        NSLog(@"Error saving parent");
                    }
                }];
            } else {
                NSLog(@"Error saving child");
            }
        }];
    }
    
    现在,您需要记住,在保存之前,在子上下文中所做的更改(例如插入的实体)将不可用于父上下文。对于子上下文,父上下文是持久存储。保存时,将这些更改传递给父级,然后父级可以将它们保存到实际的持久存储中。保存propogate