[SwiftUI][Realm][Xcode12] Realm を使ったアプリの開発方法(その4: List 表示している要素を修正する)

単体要素の修正であれば、問題なく行えます。
Realm から取得した複数要素も freeze() 指定して使うことで、List 等にも使えます。

ただし、この2つを組み合わせようとすると 少し工夫が必要となります。その工夫を説明します。

[SwiftUI][Realm][Xcode12] Realm を使ったアプリの開発方法(その1 : 要素作成) [SwiftUI][Realm][Xcode12] Realm を使ったアプリの開発方法(その2 : 要素編集) [SwiftUI][Realm][Xcode12] Realm を使ったアプリの開発方法(その3 : UNDO/REDO 実装)

これまでの復習

ここまでみてきたところで、以下のことがわかっています。

  • Realm の Object は、@ObservedObject で受けられる
  • List に渡すときは、freeze() 指定しないと、エラーになる

詳細ビューで変更するパターンへの対応

リストによって要素が列挙されている画面から、1要素をクリックして詳細画面へ遷移して、要素の編集を行うパターンは、定番の操作です。

これまでの方法では、このパターンを実装しようとするとエラーが発生してしまいます。

これまでの延長線上での実装

List に渡すときには、freeze() して渡さないといけません、また、Realm の Object は、@ObservedObject で受けられるので、
普通に作ると以下のように実装出来そうです。

ContentView

(1) で、下位ビューに移行するようにして、(2) で定義している下位ビューで、テキストを編集できるようにしています。
変更を伝播するため、(3) で @ObservedObject で受けています。

実行すると・・・

以下のようなエラーが発生します。

エラーメッセージ

理由は、以下の箇所で (a) で freeze() して渡した要素を、(b) で Binding して渡そうとしている点です。

ContentView から抜粋

Realm のドキュメントには、以下のように説明されています。

When working with frozen objects, an attempt to do any of the following throws an exception:

  • Opening a write transaction on a frozen realm.
  • Modifying a frozen object.
  • Adding a change listener to a frozen realm, collection, or object.

解決策も以下のように書かれています。

To modify a frozen object, query for it on an unfrozen realm, then modify it.

そのままですね。再度、Query しなさいとのことでした。

再 Query するように修正

準備として id から要素を取得する以下のような関数を作ります。

textLineFromID

そして、TextDetailView へ渡す TextLine を、再取得してから渡すようにします。

ContentView から抜粋 (id から TextLine 再取得)

改めて実行してみると

別のエラーが・・・・

エラーメッセージ

TextField に String の Binding を渡して変更しようとしているのですが、Realm では、Object の変更は、以下のように、write ブロックで変更しなければいけません。

Realm への書き込み

TextField には、onCommit: で編集終了時の処理を記述する方法がありますので、以下のようにします。

TextField の onCommit で Realm へ反映

MEMO
テキストを変更するコマンドを作って、onCommit で実行するほうが良いですが、省略しています。

やっと・・・

SwiftUI の期待するやり方と、Realm の期待するやり方をうまく整合させることが必要になりましたが、スムーズに動作させることができました。

参考までに、改めて、コードを提示します。

ContentView

まとめ

SwiftUI と Realm を組み合わせて使うには
  • Realm の Object は、Observable なので、そのまま使える
  • SwiftUI の List に渡すには、freeze() して渡す
  • freeze した Realm Object は、再度 Query してから、変更する
  • Realm Object は、Realm.write ブロックで変更する必要があるので、onCommit 等を使用して、自分で変更処理を行う

SwiftUI の学習のお供

SwiftUI は、GUI のライブラリでもあるので、どのようなコンポーネントかを視覚的に確認できると学習がはかどります。
以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、超便利です。

英語ですが、画面のスナップショットが多くありますので、英語を読む必要は少ないと思います。

SwiftUIViewsMastery

説明は以上です。
不明な点やおかしな点ありましたら、ご連絡いただけるとありがたいです。

コメントを残す

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