2010-07-21 51 views
1

我有一个基于Core Data的UIKit应用程序,它允许用户在屏幕上拖动对象。在拖动对象时,我会更新每个touchesMoved:事件的位置属性。为了一次性支持撤消拖动操作,我在拖动的开始处开始一个新的撤消组,并在用户抬起手指时结束组。核心数据撤消跨越多个运行循环周期的操作合并

为了节省内存和快速撤消操作,我想合并属于拖动操作的撤消数据,但是Core Data使这一点变得困难。问题是在每个运行循环周期结束时调用processPendingChanges,并强制核心数据为该迭代中发生的位置更改生成新的撤消记录。拖动操作可以轻松地累积数百个这样的撤消记录,除第一个之外,所有这些都是不必要的。

有没有办法让我继续使用Core Data的神奇内置撤销支持,但不会在这样的重复撤消记录上浪费宝贵的内存?我喜欢我不需要关心在撤销/重做操作中维护对象图一致性,但是无法正确处理这些连续的属性更新似乎是一个不争的事实。

回答

3

我认为设置撤消管理器setGroupsByEvent:会做你想做的。

设置一个布尔值,指定 是否接收机自动 组运行 循环中撤消操作。如果为“是”,则接收方在每次通过 运行循环时创建 撤消组;如果不是,它不会。

更简洁的解决方案可能是直到拖动事件结束时才将对象位置提交给数据模型。

+0

不幸的是,'setGroupsByEvent:'在这里没有帮助。拖动跨越多个事件,所以除非我误解了一些基本的东西,否则没有办法用'beginUndoGrouping' /'endUndoGrouping'明确分组我的更改 - 而'setGroupsByEvent'在已经有一个开放组的情况下变为空操作。 在拖动手势结束前不更改模型可能是最佳方式。问题是我没有地方存储瞬态位置 - 我直接从模型中进行渲染,没有单独的视图对象。但也许这只是意味着现在是时候添加它们了! – 2010-07-23 21:38:36

+0

IIRC,将'groupsByEvent'设置为'NO',您将得到一个超出运行循环的长撤销组。 – TechZen 2010-07-24 02:45:50

+0

*叹息*不,将'groupsByEvent'设置为'NO'只会禁用隐式分组,因此您需要始终启动和结束自己的组。是的,你自己创建的组显然可以超越单循环迭代。这不是问题。 问题是在每次运行循环迭代结束时自动调用'performPendingChanges'引发的内存使用情况和性能问题。您建议的更清晰的解决方案恰好是一个很好的解决方法:如果模型仅在手势结束时发生更改,则“performPendingChanges”不会在每次运行循环迭代中注册新的撤销操作。 – 2010-07-25 17:19:06

0

一种解决方案是在第一次拖动事件后禁用所有撤销注册,并保持禁用状态直到整个手势完成。

如果您有groupsByEvent,请记住撤销管理器会在注册关闭时忽略所有分组消息,包括在事件结束时自动结束隐式组的消息。所以,如果你打算请假登记在运行循环结束关掉,你就必须自己手动关闭隐性组:

[moc processPendingChanges]; 
while ([moc.undoManager groupingLevel]) 
    [moc.undoManager endUndoGrouping]; 
[moc.undoManager disableUndoRegistration]; 

一旦拖动动作完成后,您可以重新启用撤销登记用下面的代码:

[moc processPendingChanges]; 
[moc.undoManager enableUndoRegistration]; 

这个解决方案的工作原理,但它有点kludgy。 TechZen建议的更清洁:在拖动手势完成之前不要更新模型属性。

+0

事实证明,更清洁的方法并不适合我的应用程序 - 系统地将一个单独(可独立调整的)视图树与我的模型对象并行引入会导致太多并发症。我结束了使用这个更简单的解决方案。 – 2010-07-26 15:37:06