iOS開(kāi)發(fā)中的NSUndoManager的undo/redo功能(一顆后悔藥)

前言:以前保存賬戶登錄數(shù)據(jù)時(shí)用過(guò)一次CoreData,最近在研究CoreData官方demo(CoreDataBooks)的時(shí)候,發(fā)現(xiàn)了一個(gè)有意思的功能undo/redo,也就是給我們彌補(bǔ)犯下犯錯(cuò)的功能,去年在公司做個(gè)一個(gè)收銀臺(tái)的功能,到現(xiàn)在還記得在深入三層選擇支付方式(紅包,銀行卡,余額的排列組合)時(shí),用戶操作產(chǎn)生的臨時(shí)數(shù)據(jù)到底在什么時(shí)候和model中的數(shù)據(jù)同步而糾結(jié)的事。隱隱的覺(jué)得這個(gè)撤消/重做功能可以優(yōu)雅的解決那個(gè)讓我耿耿于懷的問(wèn)題,于是今天先"膚淺"的學(xué)習(xí)一下。

一、簡(jiǎn)介

幫助文檔上說(shuō),NSUndoManager就是一個(gè)通用的撤消堆棧,你可以注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng)對(duì)象的屬性改變時(shí),你可以通過(guò)調(diào)用該函數(shù),進(jìn)行撤消管理。可以看到NSUndoManager中有兩個(gè)id類型的成員變量(private) _undoStack,和_redoStack,兩個(gè)stack初始化時(shí)都是空的,里面可以存放NSInvocation類型的數(shù)據(jù),NSInvocation中大致有methodSignature,argumentsRetained,target,selector這些屬性。它封裝了消息事件的一些信息。最關(guān)鍵的大概就是這幾句話:initially, both stacks are empty. Recording undo operations adds to the undo stack, but the redo stack remains empty until undo is performed. Performing undo causes the reverting operations in the latest group to be applied to their objects. Since these operations cause changes to the objects’ states, the objects presumably register new operations with the undo manager, this time in the reverse direction from the original operations. Since the undo manager is in the process of performing undo, it records these operations as redo operations on the redo stack. Consecutive undos add to the redo stack. Subsequent redo operations pull the operations off the redo stack, apply them to the objects, and push them back onto the undo stack.大概意思就是,當(dāng)進(jìn)行一次操作時(shí),undo operations記錄著與當(dāng)前操作相反信息的NSInvocation壓入到_undoStack中,當(dāng)進(jìn)行undo operations時(shí),_undoStack的棧頂元素出棧,記錄著與棧頂元素的反相操作的NSInvocation壓入到_redoStack中(這時(shí)NSInvocation中的信息是與原操作一樣的,負(fù)負(fù)得正的原理)。

三、簡(jiǎn)單的實(shí)現(xiàn)

系統(tǒng)提供了- (void)registerUndoWithTarget:(id)target selector:(SEL)selector object:(nullable id)anObject、- (id)prepareWithInvocationTarget:(id)target,- (void)registerUndoWithTarget:(id)target handler:(void (^)(id target))undoHandler最后一種是iOS9新加入的,幫助文檔上說(shuō),- (id)prepareWithInvocationTarget:(id)target方法執(zhí)行時(shí)會(huì)調(diào)用- (void)forwardInvocation:(NSInvocation *)anInvocation。這就說(shuō)明NSUndoManager重載了該方法。我們知道,當(dāng)方法找不到函數(shù)體時(shí)在crash前會(huì)走轉(zhuǎn)發(fā)流程,轉(zhuǎn)發(fā)時(shí)在調(diào)用- (void)forwardInvocation:(NSInvocation *)anInvocation前會(huì)調(diào)用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法,如果在我在測(cè)試的類中實(shí)現(xiàn)該方法,是能夠被調(diào)用的。假如我注冊(cè)一個(gè)變量a,并且對(duì)他注冊(cè)一個(gè)撤消操作,當(dāng)a值改變時(shí),我是可以進(jìn)行撤消 的,當(dāng)撤消后通過(guò)redo可以重做。接下來(lái)貼出幾行簡(jiǎn)單的代碼:

registerUndoWithTarget:
prepareWithInvocationTarget:

? 另外我們還可以為NSUndoManager添加一個(gè)通知中心,來(lái)監(jiān)聽(tīng)其狀態(tài)的變化,需要注意的是在何時(shí)的地方移除監(jiān)聽(tīng)。

NSNotificationCenter

總結(jié):理解英文文檔有點(diǎn)費(fèi)勁,如果有理解錯(cuò)誤的地方敬請(qǐng)批評(píng)、指出,demo功能過(guò)于簡(jiǎn)單(也是為了更好的理解),我會(huì)持續(xù)更新,共同學(xué)習(xí)進(jìn)步.demo地址:https://github.com/luguoliang/Model.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容