
原文链接:http://nshipster.com/nsundomanager/
前言Foundation框架中的NSUndoManager为我们提供了去撤销与重复 *** 作的健壮API。
默认的话,每个应用窗口都有一个撤销管理者,并且在响应者链的任意对象可以管理一个自定义的撤销管理从而实现对本地各自视图撤销和重复 *** 作。除了UITextFIEld和UITextArea自动配有撤销功能之外,其余对苹果开发者都是一个待修的课题。
要想进行一个动作撤销,要先注册一个“撤销 *** 作”。
注册一个简单的撤销 *** 作调用NSUndomanger -registerUndoWithTarget:selector:object:到要执行撤销 *** 作的对象上。同时指定一个撤销动作的名字,使用NSUndoManager -setActionname:。撤销对话框展示动作的名字,所以必须本地化。
func updatescore(score: NSNumber) { undoManager.registerUndoWithTarget(self,selector:Selector("updatescore:"),object:score) undoManager.setActionname(NSLocalizedString("actions.update",comment: "Update score")) myMovIE.score = score} 通过NSInvocation来注册一个复杂的撤销 *** 作 简单得撤销 *** 作可能让功能过于呆板了,因为撤销一个动作可能需要的参数不止一个。在这种情况下,我们可以拔高通过NSInvocation来记录选择器与必要的参数。调用prepareWithInvocationTarget:记录哪个对象将要收到XX将要变化的消息。
func movePIEce(pIEce: ChesspIEce,row:UInt,column:UInt) { let undoController : VIEwController = undoManager?.prepareWithInvocationTarget(self) as VIEwController undoController.movePIEce(pIEce,row:pIEce.row,column:pIEce.column) undoManager?.setActionname(NSLocalizedString("actions.move-pIEce","Move PIEce")) pIEce.row = row pIEce.column = column updateChessboard()} 这里的原理是NSUndoManager实现了forwardInvocation:。在撤销管理者收到撤销-movePIEce:row:column:的消息的时候,因为自身没有实现这个方法的缘故它将这个消息丢给了目标对象。
注册完撤销 *** 作以后就可以愉快的使用NSUndoManager -undo and NSUndoManager -redo进行撤销重做进行玩耍了。
默认的,用户在摇晃设备的时候出发撤销 *** 作。如果视图控制器需要响应撤销请求,那么视图控制器需要:
能够成为第一响应者 当视图出现得时候成为第一个响应者 当视图消失的时候脱离第一响应者当视图控制器接收到动作事件, *** 作系统会d出一个对话框让用户选择是不是执行撤销或者重做的动作。(如果有这个功能的话)视图控制器的undoManager属性会完成用户做好选择后的活儿。
class VIEwController: UIVIEwController { overrIDe func vIEwDIDAppear(animated: Bool) { super.vIEwDIDAppear(animated) becomeFirstResponder() } overrIDe func vIEwWilldisappear(animated: Bool) { super.vIEwWilldisappear(animated) resignFirstResponder() } overrIDe func canBecomeFirstResponder() -> Bool { return true } // ...} 自定义撤销栈 组动作 所有的撤销 *** 作注册到同一个run loop中会导致都不执行,除非指定一个“撤销组”。组的概念让撤销和重做的动作可以同时一起进行。尽管所有的动作可以被单独的执行以及撤销,如果用户同时执行两个 *** 作,同时撤销两个有利于保留用户体验一致性。
func readAndArchiveEmail(email: Email) { undoManager?.beginUndoGrouPing() markEmail(email,read: true) archiveEmail(email) undoManager?.setActionname(NSLocalizedString("actions.read-archive",comment:"Mark as Read and Archive")) undoManager?.endUndoGrouPing()}func markEmail(email: Email,read:Bool) { let undoController: VIEwController = undoManager?.prepareWithInvocationTarget(self) as VIEwController undoController.markEmail(email,read:email.read) undoManager?.setActionname(NSLocalizedString("actions.read",comment:"Mark as Read")) email.read = read}func archiveEmail(email: Email) { let undoController: VIEwController = undoManager?.prepareWithInvocationTarget(self) as VIEwController undoController.moveEmail(email,toFolder:"InBox") undoManager?.setActionname(NSLocalizedString("actions.archive",comment:"Archive")) moveEmail(email,toFolder:"All Mail")} 清空栈 有时候需要清理撤销管理者的动作列表来避免造成用户混淆从而导致其预期不到的结果。最常用的方式是党上下文动态变化的时候,比如改变iOS上可见的视图控制器或是打开了一个文件夹。当此类情况发生的时候,我们可以调用NSUndoManager -removeAllActions or NSUndoManager -removeAllActionsWithTarget:来清理我们的撤销管理者栈。
如果一个动作对应多个撤销与重做,要核对所设置的 *** 作名称以确保撤销对话框所反映的行动将被撤销称号的前撤消 *** 作是否已经发生。下面栗子展示一对反 *** 作,比如添加和删除对象:
func addItem(item: NSObject) { undoManager?.registerUndoWithTarget(self,selector: Selector("removeItem:"),object:item) if undoManager?.undoing == false { undoManager?.setActionname(NSLocalizedString("action.add-item",comment: "Add Item")) } myArray.append(item)}func removeItem(item: NSObject) { if let index = find(myArray,item) { undoManager?.registerUndoWithTarget(self,selector: Selector("addItem:"),object:item) if undoManager?.undoing == false { undoManager?.setActionname(NSLocalizedString("action.remove-item",comment: "Remove Item")) } myArray.removeAtIndex(index) }} 如果你使用像是Kiwi的测试框架,那么请在用例teardown中进行撤销栈的清除。不然其他的测试用例将会共享当前用例的撤销状态并且用例中调用NSUndoManager -undo会导致意想不到的结果。
以上是内存溢出为你收集整理的Cocoa中的NSUndoManager全部内容,希望文章能够帮你解决Cocoa中的NSUndoManager所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)