[SwiftUI][CoreData] SwiftUI と MVVM で始める CoreData 入門 (その9:TODOItem を編集可能に)

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

環境&対象

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

  • macOS Catalina 10.15.7
  • Xcode 12.2
  • iOS 14.2

既存 TOODItem の編集

既存の TODOItem を編集できるようにする

モデルのアップデート

既存の TODOItem のプロパティをアップデートするメソッドを作ります。

まずは、モデルテストから作ります。

モデルテスト

既存の TODOItem の Title, Detail, isDone を変更できることを確かめます。

Model 追加テストコード

TODOItem のプロパティ値を CoreData (DB layer) に反映するメソッド (updateItem) を作り、id を使って、改めて fetch するメソッド (refetchItem) も作ります。

Model 追加コード

テストを実行するとパスすることを確認できます。

以前に、isDone をアップデートするメソッド(toggleIsDone)を作っていましたが、今回作った updateItem を使うようにします。

TODOItemStore.toggleIsDone

これまでの全てのテストをパスすることを確認してモデルの修正は、終わりです。

View, ViewModel のアップデート

まずは、View のテストを作ります。

新規 TODOItem 作成シートを再利用して、TODOItem の編集を行う方針で作ることにします。

View,ViewModel 向けテスト作成

View のテストとして、新規 TODOItem 作成後に、詳細ビューに移行して、プロパティを変更してみます。

test_editTODOItem_withNewPropertyValue_shouldBeStored

# 要素がうまく取得できない時があり、sleep を適宜入れています。

これに合わせて、以下の修正が、PageObject に必要となります。

  • 新規 TODOItem 作成ビュー用の TODOListNewItemPageObject に、isDone を操作できる Toggle を追加(名前も TODOListItemDetailPageObject に変更しました)
  • メインビューを表す TODOListPageObject に、行をタップすると TODOItem の詳細ビューに遷移するメソッドの追加

ここで、以下の不整合に気づきます。

  • 行をタップした時に、isDone を toggle するのか、詳細ビューに遷移するのか、どっち?

これまでは、行をタップしたときに toggle していましたが、行タップは、詳細ビューへの遷移。チェックボックスをタップしたときに、toggle するような動作に変更します。(テスト的には、チェックボックスを操作していましたが、View としては、行をタップされても動作していました)

”TODOListNewItemPageObject
コード解説
  1. isDone の状態を表す Toggle を取得できるようにします
  2. Title, Detail, isDone の状態を返すメソッド
  3. isDone の状態を表す Toggle をタップするメソッド

TODOListPageObject も、行をタップして、詳細ビューへ遷移するメソッドを追加します。

TODOListPageObject 修正

コード解説
  1. 新規作成にも、同じビュー View の使うようにします
  2. メインビューの行を表す Page Object を返します。この TODOItemRowPageObject が tapToDetailVew メソッドを提供します

コンパイルは通る状態になります。(テストをパスはしません)

View を変更

テストができたので、変更を行います。

  • NavigationLink を使って、行タップ時に、TODOItem の詳細ビューへ遷移
  • 詳細ビュー(NewTODOItemView)に isDone を表現する Toggle を追加
  • NavigationLink の Label 要素内をうまく XCUIElement で走査できないので、チェックボックスを NavigationLink 外へ移動
  • 上記と同じ理由で、テストを変更。プロパティの妥当性は、詳細ビューに遷移して確認(メインビューでの表示の正しさは目視しかできなくなりました)
TODOItemView
コード解説
  1. NavigationLink の Label 内に含まれると 走査不能になってしまうので、チェックボックス用の Image を外部に出しました
  2. Accessibility ID で取得できなくなったので、ID 設定も止めています
TODOITemDetailView
コード解説
  1. 編集時には、渡される TODOItem を保持します
  2. 新規作成時には、nil が渡されますが、既存要素編集時には、該当 item が渡されます。内部の State 変数に必要に応じて値をコピーしておきます。このビュー内での編集対象は、editItem です。
  3. OK が押された時には、新規作成/既存編集に応じて、新規作成・プロパティアップデートを行います。
MyTODOMainView
コード解説
  1. チェックボックスイメージを NavigationLink 外部に出しています
  2. NavigationLink から TODOItemDetailView に遷移するときは、該当 TODOItem を渡します。
  3. 新規作成時には、TODOItemDetailView に nil を渡します。
  4. GUI 要素の配置を少し調整しました。

これで、TODOItem について、 いわゆる CRUD することができるようになりました。

動かすと以下のような感じのアプリになっています。

普通に使える気がするので、これを Version1 にして、追加機能は、データ互換性も考慮しつつ実装していくことにします。

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

コメントを残す

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