撤消从主线程执行的核心数据插入

时间:2011-02-09 02:23:25

标签: objective-c cocoa core-data nsoperation nsmanagedobjectcontext

我正在研究一些使用NSOperation导入数据的代码。我希望用户能够撤消导入操作期间创建的NSManagedObject实例。

据我所知,对于从主线程执行的任何操作,都不可能使用NSManagedObjectContext -undoManager。从使用线程限制来支持并发核心数据编程指南部分,我们有以下两个条件:

  
      
  1. 只应传递objectID   托管对象上下文之间(on   单独的线程)
  2.   
  3. 托管对象   必须先保存在上下文中   可以使用objectID。
  4.   

这是有道理的,因为托管对象需要从私有存储(NSManagedObjectContext)移动到公共存储(NSPersistentStore)才能共享。

不幸的是,-save:消息还会导致撤消堆栈中的任何托管对象被删除。从同一指南的使用核心数据的内存管理部分:

  

具有待处理的托管对象   变化(插入,删除或   更新)由其上下文保留   直到他们的上下文发送保存:   重置,回滚或dealloc消息,   或适当数量的地址   撤消更改。

我已经尝试了几个方法来解决这个限制,并且所有事情最终都会导致主线程(以及旋转沙滩球)上发生的大量工作。任何线索都要撤消使用主线程创建的对象非常感谢。

-

已提交增强型雷达:rdar://problem/8977725

5 个答案:

答案 0 :(得分:2)

这个答案可能会有点来回。如果我正确理解了这个问题,那么您正在进行导入,但是在导入完成后,您希望用户能够选择从导入中保存的内容吗?

如果这不正确,请修正我的假设,我会更新此答案。

如果它是正确的那么你可以做的是:

  1. 将您的背景对象创建更改为

    NSEntityDescription *myEntity = ... //Entity from your context
    [[NSManagedObject alloc] initWithEntity:myEntity
             insertIntoManagedObjectContext:nil];
    
  2. 将这些实体存储在一个数组中。
  3. 根据需要将实体传回主线程。
  4. 发布您不想保留的任何对象
  5. 在您要保留的任何内容上致电[myMainContext insertObject:managedObject]
  6. NSManagedObjectContext
  7. 上执行保存

    由于这些实体不是NSManagedObjectContext的一部分,但它们只存在于内存中, 应该是线程安全的,因为它们尚未绑定到NSManagedObjectContext

    这当然是理论上的,需要进行测试。但它应该实现你的目标。

答案 1 :(得分:0)

不是专家,但我认为您需要做的是创建第二个上下文来执行操作,然后将两个上下文合并在一起。您应该能够将合并作为撤消步骤进行管理。请注意,这仅在您将整个操作集视为一个撤消步骤时才有效。就用户而言。

答案 2 :(得分:0)

假设您为后台线程使用单独的上下文,一旦完成,将[[backgroundContext undoManager] undo]推送到前台线程的撤消堆栈?我从来没有尝试过这样的事情,但是我无法想到它应该不起作用的原因。

答案 3 :(得分:0)

一个选项可能是使您的导入线程持久化。即使线程完成导入,它也会进入空闲循环状态。这样,您的线程ManagedObjectContext将保留在正确的线程中。然后,当用户希望撤消更改时,向线程发送消息以使用undomanager。

答案 4 :(得分:0)

您很可能已经考虑过这一点,并且您可能只是在寻找使用现有undoManager的解决方案,但以防万一:

由于您正在插入对象而不更新现有对象,因此您可以在导入每个批处理时使用事务ID标记它们,并在撤消时在后台线程中删除它们。对于标记,简单递增的NSNumber就足够了。

不雅,但可行。