在Cocoa中,恢复操作(Undo)是一个很有用的功能,但是希望将它整合到Core Data中的人们知道,这个过程可能会有一点令人沮丧。
通常来说,你不需要在意Undo功能,这个内建的功能就可以直接被支持。但是如果你使用了Core Data,情况就会变得复杂一些。
这是一篇cimgf的优秀作品,cocoachina将其翻译过来,帮助国内读者更容易阅读。
作者:Marcus Zarra
原文地址:http://www.cimgf.com/2008/04/30/cocoa-tutorial-wiring-undo-management-into-core-data/
与NSUndoManager冲突
如果你使用过Cocoa的Undo功能的话,你应该清楚所有的恢复操作都是注册到NSUndoManager中的。在一个普通的基于文档的程序中,窗口的托管会提供给NSUndoManager窗口中包含的所有文本框和其他可编辑内容。
但是如果加入了Core Data,情况就不一样了。原因是NSManagedObjectContext有自己的NSUndoManager,注册了同样的消息,所以我们就很难控制恢复操作。
我希望的情况是尽量避免有两个NSUndoManager,而仅仅使用NSManagedObjectContext自带的那个。通过下面窗口托管方法中的代码,可以实现这个功能:
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window
{
return [self undoManager];
}
- (NSUndoManager*)undoManager
{
return [[self managedObjectContext] undoManager];
}
通过使用包含在NSManagedObjectContext中的NSUndoManager,我们就可以使用一些非常有用的功能了。
使用分组对数据进行修改
正常的界面设计可以在一个弹出窗口中编辑对象。用户可以双击物件,也可以点击。点击对象表示他们希望编辑其中的内容,我们可以弹出一个窗口让他们修改其内容。那么自然弹出的这个窗口中也包含了一个NSUndoManager(也可以使用Core Data中自带的),这样,每个编辑框中的内容都可以恢复。不过,我们如何处理“取消”按钮,或者如何取消整个弹出窗口中内容的编辑呢?
上面所提的两个问题都可以使用在NSManagedObjectContext对象中的NSUndoManager里提供的分组功能实现。通过以下代码可以做出这种效果:
- (void)presentEditSheet:(id)sender
{
[[self undoManager] beginUndoGrouping];
[NSApp beginSheet:[self editSheet]
modalForWindow:[self window]
modalDelegate:nil
didEndSelector:NULL
contextInfo:nil];
}
- (void)acceptChanges:(id)sender
{
[[self editSheet] orderOut:sender];
[NSApp endSheet:[self editSheet]];
[[self undoManager] endUndoGrouping];
[[self undoManager] setActionName:@"Object edit"];
}
- (void)cancelChanges:(id)sender
{
[[self editSheet] orderOut:sender];
[NSApp endSheet:[self editSheet]];
[[self undoManager] endUndoGrouping];
[[self undoManager] undo];
}
在例子里,在显示弹出窗口之前,我启用了beginUndoGrouping方法。在窗口关闭后,我结束分组,如果用户没有点击窗口中的“取消”按钮,我就给这个分组设置一个名称。这个名称会在菜单中显示,并且可以一键恢复所有在弹出窗口中所做出的改动。
如果用户点击了“取消”按钮,那么分组结束了,不过同时我直接调用了恢复-undo方法,这样,在窗口中进行的编辑立刻就被取消掉了。
结论
仅仅使用一个NSUndoManager非常简单,而且可以给用户提供一致的结果。上文所述的这个方法还可以用于基于文档但是每个文档都带有一个NSUndoManager关联到文档自身的NSManagedObjectContext中的程序中。
如果你有其他使用NSUndoManager的方式,可以在本站或这里留言,或者直接给作者发邮件:marcus at cimgf.com