11

//编辑:真的,没有人对此有任何建议或想法吗?我是否以某种方式错误地问了这个问题?//

我的 iPhone 应用程序有一个 managedObjectContext 和一个中等复杂的数据模型。我现在正在添加撤消功能,但不清楚如何最好地处理嵌套的视图控制器(因为每一层都可能修改数据模型)。

Apple 的文档指出:“考虑一个显示书籍列表的应用程序,并允许您导航到详细视图,进而允许您编辑书籍的各个属性(例如书名、作者和版权日期)。您可以从列表屏幕创建一本新书,在其他两个屏幕之间导航以编辑其属性,然后导航回原始列表。如果列表视图中的撤消操作取消了对作者姓名的更改,这可能看起来很奇怪。将两个屏幕分开,而不是删除整本书。”


那么实现这一点的最佳方法是什么?目前,我正在考虑让每个 viewController 保留自己的 undoManager,只要它在屏幕上,它就会处于活动状态。所以我的理解是,这将需要以下步骤(对于每个 VC):

  • 添加属性: myUndoManager
  • 添加undoManager方法返回myManagedObjectContext.undoManager;
  • In viewDidAppear: myManagedObjectContext.undoManager = myUndoManager;// 如果为 nil,则首先创建
  • viewWillDisappearmyManagedObjectContext.undoManager = nil;
  • 关于内存警告: [self.undoManager removeAllActions ];
  • 在dealloc上: self.myUndoManager = nil;
  • 对于每个模型更改:[self.undoManager setActionName:NSLocalizedString(@“XXX”,@“”)];
  • CoreData 将处理实际的撤消/重做发布

另外,我必须保持 firstResponder:

  • viewDidAppear:`[self becomeFirstResponder]'
  • 添加canBecomeFirstResponder方法返回 YES
  • viewWillDisappear:[self resignFirstResponder];
  • 在子视图辞职时重新启用 firstResponder(例如 textFields)

到目前为止,这似乎有效,即使在加载/卸载周期中也是如此,并且非常独立,但我有几个问题:

  • 首先,这是跨多个 VC 实现撤消的最佳实践吗?
  • 我是否会因为我的子 VC 在我之前的操作之前没有进行撤消而遇到麻烦?
  • 如果是这样,该列表是否包含我需要做的所有事情?
  • ManagedObjectContext 会与多个处于活动状态的 UndoManager 混淆吗?
  • 在交换 undoManager 之前是否需要调用 ProcessPendingActions?
4

3 回答 3

1

我会非常努力地只有一个撤消管理器。
考虑以下场景:

型号:(鸡)
属性:鸡蛋、颜色、大小;

模型:(鸡蛋)
属性:鸡,颜色;

chicken.eggs = 与 egg 的一对多关系,egg.chicken 则相反。

您创建了 2 个撤消管理器,一个用于 chickenViewController,一个用于 eggViewController。
你创建了 chicken0 和它的鸡蛋:egg0,egg1。
你创建了 chicken1 和它的鸡蛋:egg2,egg3。
你删除egg2。

现在你删除 chicken1 级联删除鸡蛋。
现在你回到 eggViewController 并撤消......你想发生什么(会发生异常)。
现在你撤消 chickenViewController 和 chicken1,它的鸡蛋回来了,但是有 2 个 egg2 吗?

编辑 我稍微缓和了我的语气,假设您使用的是分层视图结构,如 UINavigationController,并且每次转到子视图时都会创建一个新的 Undo 控制器,我不认为您应该有一个问题。

于 2011-04-26T21:24:14.867 回答
0

听起来您想将一堆撤消合并为一个整体,以便它们可以作为一个整体撤消。这是通过 beginUndoGrouping 和 endUndoGrouping 完成的。有什么理由不能使用它吗?我不确定您是否可以在组中间撤消一个步骤,所以这将是一个问题。

于 2011-04-02T04:34:06.433 回答
0

每个视图控制器都可以有自己的撤消管理器。控制器应该只对它直接更改的字段负责。一旦你退出相应的视图,控制器和撤消管理器应该被释放。

假设您有 3 个级别。级别 1 代表整个记录,级别 2 代表级别 1 的数据子集,级别 3 代表级别 2 的数据子集。

一旦您退出第 3 级,您基本上就说我接受并且您不需要撤消第 2 级中的任何数据。如果更改的数据显示为全部。同样,一旦退出级别 2,您应该释放其撤消管理器。

回到第 1 级,既然它代表整个记录,为什么不使用取消按钮而不是尝试撤消(或除此之外,取决于您的 1 级控制器所做的事情)?

然后,如果要取消整个操作,可以向托管对象上下文发送如下消息:

[myMOC refreshObject:theEditedObject mergeChanges:NO];

这将有效地回滚整个记录

如果出于某种原因,您决定在级别 2 中保留级别 3 的撤消管理器,并且您在级别 2 进行回滚,则只有与级别 2 的撤消管理器相关的数据会被回滚。Level 3 的 undo manager 是独立的,Core Data 并不认为 undo manager 是嵌套的。

托管对象上下文不会因为多个撤消管理器而混淆,因为它一次只能通过其setUndoManager:方法跟踪一个。

您可能不需要使用processPendingChanges,除非在进行更改后在事件循环完成之前以某种方式发生回滚。我不会担心这一点,除非您的撤消只恢复了一些应该由撤消管理器记录的数据。

于 2011-06-04T19:00:40.443 回答