CoreData NSUndoManager 关系问题

Posted

技术标签:

【中文标题】CoreData NSUndoManager 关系问题【英文标题】:CoreData NSUndoManager issues with relationships 【发布时间】:2015-09-13 19:09:39 【问题描述】:

我有一个与 Department 具有多对一关系的托管对象 Employee。因此,一个员工可以在一个部门中,但部门可以包含多个员工。

我使用撤消管理器来注册某些员工的删除。之后我关闭撤消注册我删除了部门。部门删除会删除所有剩余的员工,因为它设置了Cascade Delete 规则。

NSManagedObjectContext *defaultContext = [NSManagedObjectContext MR_defaultContext];        
NSUndoManager *undoManager = [defaultContext undoManager];

[undoManager enableUndoRegistration];
[undoManager setActionName:@"Delete"];

[employee MR_deleteEntityInContext:defaultContext];

// let undo manager finish registering events on current run loop
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
[undoManager disableUndoRegistration];

// ...

// somewhere later without undo manager enabled
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) 
   Department *department = [departmentOnMainThread MR_inContext:localContext];
   [department MR_deleteEntityInContext:localContext];
];

然后我撤消 Employee 的删除,它在我的上下文中与 Department 一起复活。

NSManagedObjectContext *defaultContext = [NSManagedObjectContext MR_defaultContext];        
NSUndoManager *undoManager = [defaultContext undoManager];

[undoManager enableUndoRegistration];
[undoManager undo];

[defaultContext MR_saveToPersistentStoreAndWait];

// let undo manager finish registering events on current run loop
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
[undoManager disableUndoRegistration];

有趣的是,当我运行 undo 时,我的上下文的 [defaultContext deletedObjects] 包含 Department、我最初使用 NSUndoManager 捕获的 Employee 以及可能与 Department 一起被删除但实际上并未捕获更改的其他一些 Employee在删除原始员工期间。这个其他 Employee 的所有字段都设置为 nil。

出于好奇,我打电话给[defaultContext refreshAllObjects],回复如下:

CoreData:警告:NSManagedObjectContext 委托覆盖错误 处理行为以静默删除具有 ID 的对象 '0xd000000000280000 ' 和 用 nil/0 代替所有属性值,而不是抛出。

问题是,可能其他 Employee 应该真的被删除了,但是我怎样才能恢复原来的 Employee 和 Department 显然应该放回数据库?

NSUndoManager 将它们恢复为已删除的对象,这没有多大意义。

【问题讨论】:

请澄清:1. 从Department 实例到Employee 实例之间存在1:n 关系,而不是相反。 2. 员工的删除和该动作的撤消操作是自动注册的还是你有明确的代码?如果是这样,请发布代码。 3. 你先删除属于某个部门的员工,然后再删除还有员工的部门? 4. 您想先撤消第一个操作,然后再撤消第二个操作? 你运行的是什么版本的 Xcode?​​span> @AminNegm-Awad 1. 正如我在一个部门很多员工之前所说的那样。 2. 我只注册第一次删除员工。从其他未启用撤消注册的控制器中删除的部门。 3. 我先删除了一个启用了撤消经理注册的员工,然后我删除了部门“账外”,然后我撤消了。 4. 我想撤消已删除的员工与部门,而不管整个部门后来与所有员工一起被删除。我希望部门在一个员工的情况下复活。 @MarcusS.Zarra Xcode 7 GM 但这可能并不重要。 1.好的,但你在第一句话中说的完全相反。也许你想纠正它。 2.请添加删除和撤消注册的代码。 4. 不能撤销不是最后一个操作的操作。它是一个带有 push 和 pop 的撤销堆栈,但没有“索引访问”。 【参考方案1】:

正如Amin Negm-Awad所指出的:

您无法撤消具有后续操作的操作。撤消 在许多情况下,预测行动是不可能的,当然也不是 支持的。 (即撤消对员工的删除不能带来 返回他们所属的部门。)您必须注册所有操作 或者没有,否则你与框架作斗争。它仍然是一个堆栈,并且 当我写下一条评论时,这将是一个堆栈。因此显然 您不能选择用于撤消的操作和不用于的操作 撤消。所以注册所有操作并使用撤消组。

【讨论】:

以上是关于CoreData NSUndoManager 关系问题的主要内容,如果未能解决你的问题,请参考以下文章

自动保存不适用于 UIManagedDocument 上的 NSUndoManager

NSUndoManager 检测核心数据实体的实际删除

一一保存 NSUndoManager 事务

iOS 4 应用程序终止和撤消

在 CoreData 应用程序上摇动撤消工作,但没有显示撤消/重做提示

NSUndoManager 灾难