[SwiftUI] Document App の隠れた制約(FileDocument の制約)

SwiftUI

Xcode12 から導入されている Document App タイプの制約について気づいたことを説明します

環境&対象

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

  • macOS Big Sur 11.1
  • Xcode 12.3
  • iOS 14.2

Document App

Xcode12 から、Xcode でのプロジェクトのタイプに Document App というタイプが登場しました。

厳密には以前からもありましたが、新しい要素である DocumentGroup や FileDocument を用いたテンプレートで生成されるようになりました。

Document という形でデータを保存する時に使いたくなるのが、CoreData や Realm 等の DB レイヤーに相当するモジュールです。

これらのモジュールとの組み合わせ方法を調べていて気づいたことを説明します。

FileDocument

新しく、ファイル選択ダイアログを表示してくれる DocumentGroup は、見た目には新しいのですが、機能的には大きな要素は占めていません。

Document App でキーとなるのは、FileDocument protocol です。

Protocol としては、非常にシンプルで1つの initializer と 1つの インスタンスメソッドが定義されています。

init(configuration:)

initializer です。configuration には、contentType:UTType と file:FileWrapper が保持されています。

これらの情報を使って、FileDocument を initialize する必要があります。

FileWrapper 経由で ファイルの内容を取得することができます。

fileWrapper(configuraton:)

インスタンスメソッドで、保存するときに呼ばれます。

引数の configuration は、initとほとんど同じ情報が保持されています。

FileWrapper 経由で ドキュメントの内容を保存します。

考察

Read, Write いずれも FileWrapper が渡されるので、具体的なファイルの場所を気にする必要なくデータの serialization(保存) と de-serialization(読込) にフォーカスすることができそうです。

FileDocument の問題点

FileWrapper でファイルシステムを抽象化できているので、良さげなのですが、この点が問題になるケースがあります。

ファイルのパスを取得できない

FileWrapper から preferedFileName という情報を取得することはできますが、ファイルのパスを表す fileURL は取得できません。

FileWrapper の init でファイルパスを指定する必要があるので内部に保持しているはずなのですが、外部からは取得できません。

このことは、CoreData や Realm といった ファイルを指定して使用するモジュールを使用する際に問題となります。

CoreData や Realm を使用する時にファイルパスを指定することが必要となるのですが、その情報が取得できないのです。

厳密には、FileWrapper を継承した独自クラスを作成し、FileWrapper.write(to:, ...) を override すると、保存のタイミングで書き出し先の URL を取得することはできますが、後述の問題と合わせて解決策にはなりません。

FileWrapper を指定できない

FileDocument.init に渡される FileWrapper は、システムが(自動で?)判断して インスタンス化されてきます。

どの FileWrapper を使用するのかは、
macOS であれば、NSDocument.fileWrapper(ofType)、
iOS であれば、UIDocument.contents(forType) 等で指定することができました。

ですが、FileDocument では、指定することができません。

独自 FileWrapper を使うことができないため、read/write を hook して独自の方法で読み書きすることができなくなっています。

CoreData/Realm との組み合わせ

CoreData や Realm は、その性質上 ファイルを直接管理するので、FileWrapper 経由でしかアクセスを許さない FileDocument との相性は、悪いの一言です。

CoreData や Realm を使ったアプリケーションで ドキュメントタイプのものを開発する時には、NSDocument, UIDocument を使うのが、現実的です。

# 2週間以上調査してますが、これまでの結果は上記です・・・・知っていたら教えください。😂

まとめ:Document App と CoreData/Realm の相性

Document App と CoreData/Realm の相性
  • FileDocument は、FileWrapper 経由でのアクセスのみ
  • FileDocument と CoreData/Realm の相性は悪い

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

コメントを残す

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