Sponsor Link
環境&対象
- macOS Monterey 12.5 Beta
- Xcode 14.0 Beta3
- iOS 16.0 beta
DocumentGroup
DocumentGroup は、SwiftUI で Document-based App を作成するときに使用する View です。
Document-based App のルートのビューとして使用されます。
Apple のドキュメントは、こちら。
Document の種類
DocumentGroup は、2つのタイプのドキュメントを処理できるようになっています。
・FileDocument
・ReferenceFileDocument
2つのドキュメントの相違点は、Value-type であるか Reference-type であるかです。
機能面から言うと、Value-type のドキュメントである FileDocument を使用すると UNDO/REDO がサポートされますが、ReferenceFileDocument を使用するときには、自分で UNDO/REDO を実装しなければいけません。
Editor と Viewer
DocumentGroup には、エディタ向け initializer と ビューア向け initializer の2つが用意されています。
例えば、FileDocument 向けには、エディタ向け、ビューア向けとして以下の2つの initializer が用意されています。
// エディタ向け
init(
newDocument: @autoclosure @escaping () -> Document,
editor: @escaping (FileDocumentConfiguration) -> Content
)
// ビューア向け
init(
viewing documentType: Document.Type,
viewer: @escaping (FileDocumentConfiguration) -> Content
)
DocumentGroup の initializer
DocumentGroup を使うにあたり、気をつけるべき点があります。
エディタ向け initializer の newDocument の引数には、ドキュメントの initializer を与えますが、ユーザーが新規ドキュメントを選んでいるかどうかにかかわらず、常にコールされます。
例えば、ユーザーが既存ドキュメントを開こうとしても、新規ドキュメントの initializer が呼び出され、その後、既存ファイルの情報を持った ReadConfiguration 付きの initializer が呼び出されるという動作になります。
既存ファイルの読み込み
ユーザーが既存ファイルを選択したときには、init(configuration: ReadConfiguration) が呼び出されます。
これは、FileDocument, ReferenceFileDocument のどちらも同じ手順です。
ReadConfiguration についての Apple のドキュメントは、こちら。
ReadConfiguration は、contentType: UTType と file: FileWrapper で構成されています。
FileWrapper を使って、ファイルの中身を読み出していくことになります。
つまり、ドキュメントが通常のファイルであれば、configuration.file.regularFileContents とすることで、ファイルのデータが読み出せることになります。
ファイルへの書き出し
ユーザーが、ファイル保存を選択したときに、fileWrapper() が呼び出されます。
この呼び出しは、FileDocument, ReferenceFileDocument のどちらも同じですが、引数と手順が少し異なっているので注意が必要です。
FileDocument の書き出し
FileDocument での書き出しはシンプルです。
fileWrapper(configuration: WriteConfiguration) が呼び出されます。
WriteConfiguration は、contentType: UTType と existingFile: FileWrapper? で構成されています。
セーブしたことのない FileDocument では、existingFile は、nil になっていますので、必要に応じて 自分で FileWrapper を生成する必要があります。
その後、FileWrapper に対して、データを保存することで、ファイルへの書き出しになります。
# ユーザーが指定したファイル名は、SwiftUI 側で管理されているため、書き出し側で配慮する必要はありません。(逆にいうと、知ることはできないようです。)
FileReferenceDocument の書き出し
ReferenceFileDocument での書き出しは、少し複雑になっています。
fileWrapper(snapshot: Snapshot, configuration: WriteConfiguration) が呼び出されます。
引数が追加され 複雑になっている理由は、ドキュメントが Reference-Type であるからです。書き出し作業はバックグラウンドで実行されるため、書き出し途中で変更が入ったときに 不整合が発生してしまうことが予想されます。
そのために、一度、Snapshot と呼ばれるデータを用意し、そのデータを書き出す形になります。
このことが、ReferenceFileDocument 型自体に Snapshot という associatedtype が設定されている理由です。
そのため、ファイル保存のステップが少し増えて以下のような手順になっています。
1. ReferenceFileDocument.snapshot が呼び出される
2. Snapshot を引数として、fileWrapper(snapshot: Snapshot, configuration: WriteConfiguration) が呼び出される
まとめ
DocumentGroup とそこで扱われる FileDocument, ReferenceFileDocument を説明しました。
- DocumentGroup には、Editor 向けと Viewer 向けの initializer が用意されている
- Document は、FileDocument と ReferenceFileDocument に大別される
- FileDocument は Value-type のドキュメント
- ReferenceFileDocument は、Reference-type のドキュメント
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
SwiftUI おすすめ本
SwiftUI を理解するには、以下の本がおすすめです。
# SwiftUI2.0 が登場したことで少し古くなってしまいましたが、いまでも 定番本です。
Sponsor Link