4

私が取り組んでいるアプリでは、ユーザーがいくつかのアセットを管理できます。ユーザーは、画面上でアセットを作成/削除/編集/分割/移動できます。ユーザーは、これらすべてのステップを元に戻すことができる必要があります。

アセットはコア データで管理されます (はい、undoManagerインスタンス化されます)。

これらのアクションごとに、次のペアで元に戻すグループを作成します。

beginUndoGrouping ... endUndoGrouping

Here's a simple example (sequence 1):
// SPLIT
- (void) menuSplitPiece: (id) sender
{
    [self.managedObjectContext.undoManager beginUndoGrouping];
    [self.managedObjectContext.undoManager setActionName:@"Split"];
    //... do the split
    [self.managedObjectContext.undoManager endUndoGrouping];
    // if the user cancels the split action, call [self.managedObjectContext.undoManager undo] here;
}

edit についても同じことを行います。ユーザーが編集をキャンセルした場合は、 の直後に undo を呼び出しますendUndoGrouping

1 つの例外を除いて、すべてが正常に機能します。私が作成したグループの他に、Core Data によって作成された、私が制御できない他のグループがあります。これが私が意味することです:

次のように NSUndoManagerDidCloseUndoGroupNotification 通知を受け取るように登録しました。

- (void) registerUndoListener
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(didCloseUndoGroup:)
                                               name:NSUndoManagerDidCloseUndoGroupNotification object:nil];
...}

これらの通知を使用して元に戻すボタンを更新し、何らかのアクションの結果として元に戻されているアクションの名前を表示します: Undo Split など

それでも、didCloseUndoGroup上記のアクションごとに 2 回呼び出されたり、通知されたりします (例: endUndoGrouping の後のセクション 1):

最初の通知の時点では、self.managedObjectContext.undoManager.undoActionName私が設定した元に戻すアクションの名前が含まれていますが、2 回目undoActionNameは空の文字列です。

回避策として、名前が空の操作を単純に元に戻して (それらが私のものではなく、必要がないと仮定して)、何か不足していないかどうかを確認しようとしました。

さて、didCloseUndoGroupこんな感じ

- (void) didCloseUndoGroup: (NSNotification *) notification
{
...
    if ([self.managedObjectContext.undoManager.undoActionName isEqualToString:@""]){
        [self.managedObjectContext.undoManager undo];
    }
    [self refreshUndoButton]; // this method displays the name of the undo action on the button
...
}

そして、魔法のように機能します。「元に戻す」を使用して、任意のコマンド、任意の数のレイヤーを元に戻すことができます。しかし、これはうまくいくはずの方法ではありません...

その前に私が試した他のいくつかのこと:

  1. [self.managedObjectContext processPendingChanges] グループを開く前に。まだ2つの通知を送信していました。
  2. 私が試した別のことは、disableUndoRegistration / enableUndoRegistration でした。これは例外を生成しました:「無効な状態です。ネストされた元に戻すグループが多すぎる状態で元に戻すが呼び出されました」

上記のどれも、前に述べた謎のグループを「分離」するのに役立ちませんでした。

NSUndoManagerDidCloseUndoGroupNotification 通知を 2 回受け取るべきではありません。または、私はすべきですか?この状況に対処するためのより良い方法はありますか?

更新 これが最終的に機能したものです。以前は、通知を受け取るとすぐに名前のないグループを自動的に取り消していました。これが問題の原因です。ここで、ターゲット グループに到達するまですべてを元に戻し、その後、そのグループの最後の元に戻します。

「undoManagerHelper」は、スタックにプッシュされるコマンドごとに一意の ID を生成する単なるスタック管理システムです。この一意の ID を使用して、グループに名前を付けます。

- (BOOL) undoLastAction
{
    NSString *lastActionID = [self.undoManagerHelper pop]; // the command I'm looking for
    if (lastActionID == nil) return false;

    //... undo until there is nothing to undo or self.managedObjectContext.undoManager.undoActionName equals lastActionID

    //the actual undo here
    if ([currentActionID isEqualToString: lastActionID] && [self.managedObjectContext.undoManager canUndo]){
        [self.managedObjectContext.undoManager undo];
    }
    return true;
}

- (void) beginUndoGroupingWithName: (NSString *) name
{

    [self.managedObjectContext processPendingChanges];
    [self.managedObjectContext.undoManager beginUndoGrouping];
    NSString *actionID = [self.undoManagerHelper push: name];
    [self.managedObjectContext.undoManager setActionName:actionID];
}

- (void) closeLastUndoGrouping
{
    [self.managedObjectContext.undoManager endUndoGrouping];
    [self.managedObjectContext processPendingChanges];
}
4

1 に答える 1

0

beginUndoGroupingのドキュメントによると-https ://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSUndoManager_Class/Reference/Reference.html-「デフォルトでは、元に戻るグループはで自動的に開始されます。イベントループの開始ですが、このメソッドを使用して独自のUNDOグループを開始し、他のグループ内にネストすることができます。」名前のないグループは、すべての操作を含むデフォルトの元に戻るグループです。状況に応じて、名前のないグループを無視する必要があるようです。

于 2012-10-01T18:52:31.267 に答える