NSUndoManager 體系
NSUndoManager 可撤銷操作,也可以逆向撤銷操作
undo 操作包含在 undo操作組中,也可以用 undo操作組中的動作做逆向 undo 操作。這個操作組存儲在棧中。undo manager 執(zhí)行時候方法 undo 或者 redo 時,實際上就是在執(zhí)行 undo 操作組中的操作。例如:用戶可以改變文字的字體和字體大小,應(yīng)用程序會囊括所有的字體屬性操作作為一個組,所以,當(dāng)用戶執(zhí)行 undo 時,字體和字體大小都會復(fù)原。只有undo 操作組中還有undo 動作,就會執(zhí)行 undo 操作。
redo 操作和 redo 操作組 就是存儲在一個單獨棧中的 undo操作組。
在 run loop 中 NSUndoManager 會自動創(chuàng)建 undo 組,用來存儲 undo 操作記錄,當(dāng) loop 開始時創(chuàng)建 undo 組,當(dāng) loop 結(jié)束時,關(guān)閉 undo 組,使用方法 beginUndoGrouping 和 enableUndoRegistration 創(chuàng)建額外的嵌套的 undo 組,也可以使用方法 setGroupsByEvent:來斷開默認(rèn)的 undo 組。
undo 和 Redo 棧
undo 組被存儲在棧中,老 undo 組在棧底 新 undo 組在棧頂,undo 組默認(rèn)不加限制。可以使用方法 setLevelsOfUndo 添加最大組數(shù)限制。當(dāng)超過最大限制,最老的 undo 組會被從棧底彈出。
初始情況下,undo 棧和 redo 棧都是空的,undo 操作被記錄在 undo 組中,直到 undo 執(zhí)行之前 redo 棧都保持空,執(zhí)行 undo 操作時,undo 棧頂?shù)?undo 組被應(yīng)用到對象上,一旦這個操作改變了對象狀態(tài),這時假想 對象注冊了新的 undo manager 操作,這個操作與原先的操作相反。只要執(zhí)行力 undo 操作,我們都會用 redo 棧把這個操作當(dāng)做 redo 操作記錄下來。連續(xù)的 undo 操作被加入到 redo 棧中.
當(dāng) redo 棧中彈出一個 redo 組,應(yīng)用到 對象上,undo 棧就會把這個操作加入 undo 棧中
- undo 的一般用法
- (void)setMyObjectTitle:(NSString *)newTitle {
NSString *currentTitle = [myObject title];
if (newTitle != currentTitle) {
// 注冊 undo 操作,這里注意傳值為舊值:currentTitle
[undoManager registerUndoWithTarget:self
selector:@selector(setMyObjectTitle:)
object:currentTitle];
[undoManager setActionName:NSLocalizedString(@"Title Change", @"title undo")];
[myObject setTitle:newTitle];
}
}
- undo 基于調(diào)用的用法, 可以傳入非對象參數(shù)如基本數(shù)據(jù)類型:CGFloat
- (void)setMyObjectWidth:(CGFloat)newWidth height:(CGFloat)newHeight{
float currentWidth = [myObject size].width;
float currentHeight = [myObject size].height;
if ((newWidth != currentWidth) || (newHeight != currentHeight)) {
// 同樣,這里需要傳入舊狀態(tài)的值:currentWidth, currentHeight
[[undoManager prepareWithInvocationTarget:self]
setMyObjectWidth:currentWidth height:currentHeight];
[undoManager setActionName:NSLocalizedString(@"Size Change", @"size undo")];
[myObject setSize:NSMakeSize(newWidth, newHeight)];
}
}
- 撤銷操作
[_undoManager redo];
- 復(fù)原操作
[_undoManager undo];