17

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

据我所知,不可能将NSManagedObjectContext -undoManager用于在主线程之外执行的任何操作。从Core Data Programming Guide部分的Use Thread Confinement to Support Concurrency,我们有这两个条件:

  1. 只有 objectID 应该在托管对象上下文之间传递(在单独的线程上)
  2. 托管对象必须先保存在上下文中,然后才能使用 objectID。

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

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

具有未决更改(插入、删除或更新)的托管对象由其上下文保留,直到其上下文被发送 save:、reset、rollback 或 dealloc 消息,或适当数量的撤消来撤消更改。

我已经尝试了几件事来解决这个限制,一切最终都会导致主线程上发生的大部分工作(以及旋转的沙滩球)。非常感激。

--

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

4

5 回答 5

2

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

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

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

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

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

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

这当然是理论上的,需要测试。但是,它应该可以实现您的目标。

于 2011-02-10T07:44:31.823 回答
0

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

于 2011-02-09T14:19:37.033 回答
0

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

由于您正在插入对象而不是更新现有对象,因此您可以在导入每个批次时使用事务 ID 标记它们,在撤消的情况下在后台线程中删除它们。对于标签来说,一个简单的增量NSNumber就足够了。

不优雅,但可行。

于 2011-02-10T07:56:45.713 回答
0

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

于 2011-02-09T03:20:03.273 回答
0

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

于 2011-02-09T03:26:07.883 回答