[SwiftUI][CoreData] SwiftUI と MVVM で始める CoreData 入門 (その13:UNDO/REDO 実装)

SwiftUI と CoreData を組み合わせたアプリの作り方を説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • maxOS Catalina 10.15.7
  • Xcode 12.3
  • iOS 14.2

UNDO/REDO 追加

CoreData は、特別な実装無しに UNDO/REDO ができるように作られています。

今回は、もともと 用意されている機能を使った UNDO/REDO を実装します。

UNDO/REDO 追加方針

UNDO/REDO は、Model の中で処理されることですので、Model 内部の実装とします。

UI は、ソート切り替えと同様に、Toolbar に UNDO/REDO ボタンを配置します。

Model が UNDO/REDO の機能と、 UNDO/REDO できるかの情報を提供するようにします。
その情報に応じて、ボタンが Enable/Disable になるようにします。

UNDO/REDO 実装

Foundation から提供される UndoManager が実際の UNDO/REDO の処理を担当します。

CoreData は、すでに UNDO/REDO 対応されていて、NSManagedObjectContext の保有する undoManager プロパティが UndoManager です。

macOS では、デフォルトで UndoManager を持つのですが、iOS では、デフォルトでは nil が設定されていて UNDO/REDO できなくなっています。

起動直後に このプロパティに、UndoManager をセットすることで、その後の操作が、UNDO/REDO できるようになります。

まずは、テストから記述していきます。

Model の UNDO/REDO テスト

DB の基本操作である CRUD(生成/参照/更新/削除) のうち、参照以外の 生成/更新/削除 を対象として 以下のテストを書きます。

  • 直前の操作が UNDO/REDO された状態になっているか
  • canUNDO, canREDO が適切な値か
test_undoRedo_Create_undoredoCorrectly
コード解説
  1. 通常は、MainLoop で UNDO/REDO の単位が管理されるのですが、DB レイヤーの UnitTest なので、false にセットします
  2. テスト用の要素を作成
  3. canUNDO/canREDO が適切な情報を返すかテスト
  4. UNDO 後に、適切な状態になっているかテスト
  5. REDO 後に、適切な状態になっているかテスト

以下、削除・更新 それぞれのテストです。

test_undoRedo_Remove_undoredoCorrectly

test_undoRedo_Update_undoredoCorrectly

テストが失敗することを確認して、(というかコンパイル通りません。)Model を実装していきます。

Model の UNDO/REDO 実装

実装するポイントは2つです。

  • 初期化時に、UndoManager をセットする
  • UndoManager とやりとりするメソッドを作る

init で、undoManager をセットします。(iOS では、デフォルトでは nil です)

example

コード解説
  1. UndoManager をセット

UndoManager 関連のメソッドを作成

TODOItemStore extension for UNDO/REDO

UNDO/REDO の実行以外に、ボタンを enable/disable するために canUndo/canRedo も実装します。

このコードで、先ほど作成したテストがパスすることを確認できます。

ViewModel/View の UNDO/REDO テスト

モデルのテストと同様に、CRUD のうちの CUD を対象としたテストを作成します。

test_undoRedo_Create_ShouldBeVanishedRecreated

コード解説
  1. アイテムを1つ追加して、UNDO/REDO ボタンのステータスをテスト
  2. UNDO して、状態をテスト
  3. REDO して、状態をテスト

以下のコードは、削除、更新のそれぞれをテスト。

test_undoRedo_Delete_ShouldBeRecoveredAndVanishAgain

TODOItem のプロパティを更新したときの確認は、都度 DetailView に移動して確認する必要があります。

test_undoRedo_Update_ShouldBeUpdatedAccordingly

ViewModel/View の UNDO/REDO 実装

ViewModel には、Model 同様 UNDO/REDO 関連のメソッドを追加。

View には、ツールバーを使った UNDO/REDO ボタンを追加

MyTODOViewModel extension
MyTODOMainView に追加した Toolbar

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です