可以将多个 NSUndoManager 与一个 Core-Data ManagedObjectContext 一起使用吗?

发布于 2024-10-17 06:48:59 字数 1744 浏览 4 评论 0原文

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

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

Apple 的文档指出: “考虑一个显示 书籍清单,并允许您 导航到详细视图,然后 允许您编辑个人 这本书的属性(例如它的 标题、作者和版权日期)。 您可以从以下内容创建一本新书 列表屏幕,在两个屏幕之间导航 其他屏幕来编辑其属性, 然后导航回原来的 列表。如果一个 列表视图中的撤消操作undid 作者姓名的更改 远离两个屏幕而不是 删除整本书。”


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

  • 添加一个属性: myUndoManager
  • 添加一个 undoManager 方法,返回 myManagedObjectContext.undoManager;
  • viewDidAppear 中>: myManagedObjectContext.undoManager = myUndoManager; //create first if nil
  • In viewWillDisappear: myManagedObjectContext.undoManager = nil;
  • 内存警告:[self.undoManager removeAllActions ];
  • 在 dealloc 上:self.myUndoManager = nil;
  • 对于每个模型更改:[self.undoManager setActionName:NSLocalizedString(@“XXX”,@ “”)];
  • CoreData 将处理实际的撤消/重做发布

此外,我必须保留firstResponder:

  • viewDidAppear中:`[self一成为FirstResponder]'
  • 添加canBecomeFirstResponder code> 方法返回 YES
  • viewWillDisappear 中: [self resignFirstResponder];
  • 在子视图退出时重新启用firstResponder(例如textFields)

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

  • 首先,这是实现撤消的最佳实践跨越多个风险投资?
  • 如果我的子风险投资人没有在我做之前的事情之前撤消他们的事情,我会遇到麻烦吗?
  • 如果是这样,该列表是否包含了我需要做的一切?
  • ManagedObjectContext 是否会与多个处于活动状态的 UndoManager 混淆?
  • 在交换 undoManager 之前我需要调用 ProcessPendingActions 吗?

//Edit: Really, nobody has any suggestions or thoughts on this? Have I asked the question wrongly somehow?//

My iPhone app has a single managedObjectContext with a moderately complicated data model. I'm now adding undo functionality, and am not clear on how best to handle nested viewControllers (as each layer might modify the data model).

Apple's docs point out:
"Consider an application that displays
a list of books, and allows you to
navigate to a detail view that in turn
allows you to edit individual
properties of the book (such as its
title, author, and copyright date).
You might create a new book from the
list screen, navigate between two
other screens to edit its properties,
then navigate back to the original
list. It might seem peculiar if an
undo operation in the list view undid
a change to the author’s name that was
made two screens away rather than
deleting the entire book."


So what's the best way to implement this? Currently, I'm thinking to have each viewController keep its own undoManager, which would be active whenever it's on the screen. So my understanding is that this would require the following steps (for each VC):

  • Add a property: myUndoManager
  • Add an undoManager method returning myManagedObjectContext.undoManager;
  • In viewDidAppear: myManagedObjectContext.undoManager = myUndoManager; //create first if nil
  • In viewWillDisappear: myManagedObjectContext.undoManager = nil;
  • On memory warning: [self.undoManager removeAllActions ];
  • On dealloc: self.myUndoManager = nil;
  • For each model change: [self.undoManager setActionName:NSLocalizedString(@“XXX”,@“”)];
  • CoreData will handle the actual undo/redo postings

In addition, I have to remain firstResponder:

  • In viewDidAppear: `[self becomeFirstResponder]'
  • Add canBecomeFirstResponder method returning YES
  • In viewWillDisappear: [self resignFirstResponder];
  • Re-enable firstResponder upon subViews resign (e.g. textFields)

So far, that seems like it works, even across load/unload cycles, and is nicely self-contained, but I have several questions:

  • First, is this the best practice for implementing undo across multiple VCs?
  • Will I get in trouble with my child VCs not doing their undos prior to my doing my earlier ones?
  • If so, does that list capture everything I need to do?
  • Will ManagedObjectContext get confused with multiple UndoManagers being active?
  • Do I need to call ProcessPendingActions before swapping undoManagers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

鱼窥荷 2024-10-24 06:48:59

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

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

型号:(蛋)
性状:鸡、色;

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

您创建 2 个撤消管理器,一个用于 ChickenViewController,另一个用于 EggViewController。
您创建了 Chicken0 及其鸡蛋:egg0、egg1。
您创建了小鸡 1 及其鸡蛋:egg2、egg3。
你删除egg2。

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

编辑
我在这件事上的语气稍微软化了一些
假设您使用的是分层视图结构,例如 UINavigationController,并且每次转到子视图时都会创建一个新的撤消控制器,我不认为您应该遇到问题。

I would work very hard to have only one undo manager.
consider the scenario:

model: (chicken)
properties: eggs, color, size;

model: (egg)
properties: chicken, color;

chicken.eggs = one to many relationship to egg, inverse is true of egg.chicken.

you create 2 undo managers one for chickenViewController, and one for eggViewController.
you create chicken0 and its eggs: egg0, egg1.
you create chicken1 and its eggs: egg2, egg3.
you delete egg2.

now you delete chicken1 cascade deleting the eggs.
now you go back to eggViewController and undo... what do you want to happen (exception would happen).
now you undo chickenViewController and chicken1 and it's eggs come back, but are there 2 egg2's?

Edit
I am softening my tone on this a little,
assuming that you are using a hierarchical view structure, like UINavigationController, and you make a new Undo controller each time that you go to a child view, I don't thing you should have a problem.

故事与诗 2024-10-24 06:48:59

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

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

退出级别 3 后,您基本上就表示我接受 并且您不需要在级别 2 中撤消任何数据。此更改的数据应该仅在级别 2 中显示为只读数据(如果有的话)。同样,一旦退出级别 2,您应该释放其撤消管理器。

回到第 1 级,因为它代表整个记录,为什么不使用“取消”按钮而不是尝试撤消(或除此之外,取决于您的第 1 级控制器的功能)?

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

[myMOC refreshObject:theEditedObject mergeChanges:NO];

这将有效地回滚整个记录

如果出于某种原因,您决定在处于级别 2 时保留级别 3 的撤消管理器,并且在级别 2 上执行回滚,则只会回滚与级别 2 的撤消管理器相关的数据。级别 3 的撤消管理器是独立的,并且 Core Data 不会将撤消管理器视为嵌套的。

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

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

Each view controller can have its own undo manager. A controller should only be responsible for the fields that it directly changes. Once you back out of the corresponding view, the controller should be released and the undo manager with it.

Let's say you have 3 levels. Level 1 represents the entire record, level 2 represents a subset of data from level 1, and level 3 represents a subset of data from level 2.

Once you back out of level 3, you've basically said I accept and you shouldn't need to undo any of that data in level 2. This changed data should only show up as read-only data in level 2 if it shows at all. Similarly, once you back out of level 2, you should release its undo manager.

Back in level 1, since it represents the entire record, why not have a Cancel button instead of trying to undo (or in addition to, depending on what your level 1 controller does)?

Then, if you want to cancel the entire operations you can send a message like the following to your managed object context:

[myMOC refreshObject:theEditedObject mergeChanges:NO];

This will effectively roll back the entire record.

If, for whatever reason, you decide to keep level 3's undo manager around while you're in level 2 and you do a rollback at level 2, only the data pertaining to level 2's undo manager would be rolled back. Level 3's undo manager is separate and Core Data does not see the undo managers as nested.

A managed object context can't get confused due to multiple undo managers because it can only keep track of one at a time via its setUndoManager: method.

You probably won't need to use processPendingChanges unless somehow a rollback is taking place before the completion of the event loop after a change has been made. I wouldn't worry about this unless your undo only restores some of the data that is supposed to be recorded with the undo manager up to that point.

咆哮 2024-10-24 06:48:59

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

It sounds like you want to take a bunch of undos into one lump so they can be all undone as a group. This is accomplished with beginUndoGrouping and endUndoGrouping. Is there some reason that you can't use that? I'm not sure if you can undo one step in the middle of a group, so that would be a problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文