NSUndoMangagerを使うと、簡単にアンドゥ、リドゥができて便利なことに今さらながら知りました。 画像などのデータ量の大きいものだと使えないかもしれませんが、簡単なコレクションとかならこれだけで十分実用になると思います。

使いかた

アンドゥ、リドゥしたい処理の中で、アンドゥ時の処理をNSUndoManagerのインスタンスに登録します。

下のソースの場合、addPerson:メソッドの中でNSUndoManagerのインスタンスにremovePerson:メソッドを登録しています。Personを追加したのを取り消すためにはPersonを削除する必要があるので、removePerson:メソッドをNSUndoManagerのインスタンスに登録しているのです。逆にremovePerson:メソッドには、addPerson:メソッドを登録しています。

あとは、アンドゥしたい時はNSUndoManagerのundoメソッドを、リドゥしたい時はredoメソッドを呼ぶだけです。

たったこれだけでアンドゥ、リドゥの処理が実装できるなんてすごいですね!

#import "PersonsController.h"

@interface PersonsController()
{
    NSMutableArray *_persons;
    NSUndoManager *_undoManager;
    NSUInteger _count;
}

@end

@implementation PersonsController

- (id)init
{
    self = [super init];

    if (self) {
        _persons = [NSMutableArray arrayWithCapacity:0];
        _undoManager = [[NSUndoManager alloc] init];
        _count = 0;
    }

    return self;
}

- (void)addPerson:(Person *)person
{
    if (![_persons containsObject:person]) {
        [[_undoManager prepareWithInvocationTarget:self] removePerson:person];
        [_persons addObject:person];
    }
}

- (void)removePerson:(Person *)person
{
    if ([_persons containsObject:person]) {
        [[_undoManager prepareWithInvocationTarget:self] addPerson:person];
        [_persons removeObject:person];
    }
}

- (void)undo
{
    [_undoManager undo];
}

- (void)redo
{
    [_undoManager redo];
}