2012-01-18 8 views
2

私のiPadアプリケーション(OpenGL描画アプリケーション)には多少複雑なデータモデルがありますが、取り消し/やり直し機能の実装に取り​​組んでいます。 Core Dataがデータモデルの変更を無料で元に戻すというのは好きですが、組み込みの機能が十分であるかどうかはわかりません。コアデータの取り消し/やり直し - 処理は元に戻されたものによって異なります

私は、しかし、彼らは一般的に以下のんアンドゥ/リドゥのアプリを描くに実装されている例がたくさん見てきました:

  1. undoに管理オブジェクトコンテキストを教えます。
  2. 再描画すべて変更後のデータモデルからです。

これは恐ろしく非効率的である - 私のアプリでは、私は「元に戻す」されている特定のオブジェクトに基づいて元に戻すためのアクションを実行できるようにする必要があり、多くの場合、これはキャンバスのさわやかな部分のみを意味します。

私の質問はこれです:自分の元に戻す操作を登録して、組み込みの取り消しと組み合わせて使用​​できますか?私は、この操作を元に戻すために来たとき

- (void)drawLineFromPoint:(CGPoint)startPoint toPoint:(CGPoint)endPoint 
{ 
    // Register the undo operation. 
    [[[managedObjectContext undoManager] prepareWithInvocationTarget:self] 
               removeObjectWithIndex:nextObjectIndex]; 

    // Draw the line object. 
    [self drawLineObjectWithIndex:nextObjectIndex fromPoint:startPoint toPoint:endPoint]; 

    // Save the new object to the data model. 
    [MyCoreDataHelper saveLineObjectWithIndex:nextObjectIndex fromPoint:startPoint toPoint:endPoint]; 

    nextObjectIndex++; 
} 

、呼び出しは、モデルを適宜変更を解雇されます。?たとえば、ユーザは、線を描画するとき、私は次の操作を行うと言いますかまたは、この状況では、組み込みの管理オブジェクトコンテキストを取り消し、自分自身でデータモデルの削除や編集を含むNSUndoManagerを使用して自分自身をロールバックする必要がありますか?組み込みの元に戻す/やり直しが実際に元に戻していることが分からない限り、これはひどく乱雑で複雑になる可能性があるようです。そのデータセットをUndoグループにまとめて、登録した元に戻す操作をデータモデルの変更とともにグループ化する必要がありますか?

別の編集:また、元に戻す操作の実行順序を保証できますか?つまり、コアデータの変更が保存され、元に戻す操作が登録された後にundoに電話すると、元に戻す操作が呼び出される前に削除されたエンティティが復活することを確認できますか?

+0

キャンバスの一部を更新する必要がある場合は、 - (void)setNeedsDisplayInRect :(CGRect)invalidRectを使用できません。 – sosborn

+0

いいえ、理由はいくつかあります。まず、私の描画はOpenGLを使って行われます。また、描画操作にはすべてのポイントスプライトの位置を見つけるための長い計算が必要で、描画ストロークごとにあらかじめ計算されていても、画面全体のすべてのストロークをレンダリングするには時間がかかりすぎる可能性があります。元に戻すことからどのデータが変更されたのかを知ることができるかどうか知っていますか?あなたの提案をありがとう。 – Stuart

答えて

2

元に戻すとどのデータが変更されたのか分かりますか?

は、なぜあなたは具体的に、キー NSInsertedObjectsKeyNSUpdatedObjectsKey、および NSDeletedObjectsKeyと通知の のUserInfoNSManagedObjectContext (Apple Docs)

の通知をチェックアウトしないでください。

また、元に戻す操作の順序を保証できますか?

まあ、(最初、中最終)スタックを経由して作品を元に戻すので、あなたは「必要があります」あなたの手順を追跡することができます。明らかに物事を正しく展開したい場合は、あなたがあなたのアンドゥを登録する順序で非常に特定しなければなりません。私はちょうど謎のベールの背後にあるものを見るためにアンドゥスタックをトレースに役立つ数行のコード:

id undoStack, redoStack; 
object_getInstanceVariable(undoManager, "_undoStack", &undoStack); 
object_getInstanceVariable(undoManager, "_redoStack", &redoStack); 
NSLog(@"%@", [undoStack description]); 
NSLog(@"%@", [redoStack description]); 

(Props to this site for the above code)

+0

ありがとう、これは役に立ちます。私はいくつかのことを試して、私の進歩についての最新情報を提供します。 – Stuart

0

flyweight構造を使用してください。アンドゥ/リドゥ操作の場合はIt is generally usedです。あなたが求めているのは、これを自分で行うことです。

フライウェイトは、必要なだけのデータを保存することができます。また、いつでも元の状態に戻すことができます。たとえば、フライウェイトは、編集が行われる前にピクセルデータを保存することができます。これは大量のメモリを必要としますが、シーン全体を再描画せずに簡単に元に戻すことができます。

+0

提案していただきありがとうございます。ピクセルデータを試して保存する方法はありません。これは潜在的に少数の描画ストロークの後に数MBのメモリを使用することができます。 OpenGLの頂点バッファデータを操作することで個々のストロークを元に戻す/やり直す手段がすでに用意されています。私はそれをテストし、それが効率的であることを知っています。私の問題は、一般的な「画面を再描画する」というアプローチを実装することができないことです。「ああ、ユーザーが消しゴムのストロークを取り消しただけです...私は-undoEraserStrokeを呼び出します:方法"。 – Stuart

+0

フライウェイト構造は、異なる種類のフライウェイトをフライウェイトチェーンに追加することを可能にします。これは、元に戻すのに非常に便利で、頂点バッファデータの取り消し/やり直しのための有効なメソッドが与えられていれば、非常に簡単にフライウェイトチェーンを作成できます。 探して価値のあるArrayList もあります。任意の型の無限に拡張可能な配列です(ArrayList でintを宣言しています)。それはあなたが探している目的に役立つかもしれません。 (型としてのオブジェクトのサポート、インデックスの完全削除など) – Zyerah

+0

'ArrayList '?そのJavaではないですか?私は、NSUndoManagerが作業中の作業のために最適化されていると確信したときに、私自身の元に戻す/やり直しシステムを完全に起動することをお勧めします。最悪の場合、私がやることは、管理対象オブジェクトのコンテキストに付属するものではなく、自分の「NSUndoManager」を使用して、コアデータモデルを手動で変更することです。このようにして、私は依然として呼び出しベースの取り消し機構を非常に簡単に利用することができます。もちろん、理想的には、データモデルの変更を自動的に処理するようにしたいと思います。 – Stuart