前言:以前保存賬戶登錄數(shù)據(jù)時(shí)用過一次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é)的事货葬。隱隱的覺得這個(gè)撤消/重做功能可以優(yōu)雅的解決那個(gè)讓我耿耿于懷的問題垢粮,于是今天先"膚淺"的學(xué)習(xí)一下贴届。
一、簡介
幫助文檔上說蜡吧,NSUndoManager就是一個(gè)通用的撤消堆棧粱腻,你可以注冊一個(gè)回調(diào)函數(shù),當(dāng)對象的屬性改變時(shí)斩跌,你可以通過調(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ù)得正的原理)净宵。
三敲才、簡單的實(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新加入的紧武,幫助文檔上說,- (id)prepareWithInvocationTarget:(id)target方法執(zhí)行時(shí)會(huì)調(diào)用- (void)forwardInvocation:(NSInvocation *)anInvocation敏储。這就說明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方法迫横,如果在我在測試的類中實(shí)現(xiàn)該方法,是能夠被調(diào)用的酝碳。假如我注冊一個(gè)變量a,并且對他注冊一個(gè)撤消操作矾踱,當(dāng)a值改變時(shí),我是可以進(jìn)行撤消 的疏哗,當(dāng)撤消后通過redo可以重做呛讲。接下來貼出幾行簡單的代碼:
? 另外我們還可以為NSUndoManager添加一個(gè)通知中心,來監(jiān)聽其狀態(tài)的變化返奉,需要注意的是在何時(shí)的地方移除監(jiān)聽贝搁。
總結(jié):理解英文文檔有點(diǎn)費(fèi)勁,如果有理解錯(cuò)誤的地方敬請批評(píng)芽偏、指出雷逆,demo功能過于簡單(也是為了更好的理解),我會(huì)持續(xù)更新污尉,共同學(xué)習(xí)進(jìn)步.demo地址:https://github.com/luguoliang/Model.git