パッケージ型のドキュメントを使う方法を説明します。

Sponsor Link
目次
ViewModel を作る
前回作成した FileDocument に準拠した PackageDocSwiftUIDocument をモデルとして使用します。
PackageDocSwiftUIDocument を保持するような Observable に準拠したクラスを定義します。
ViewModel DocumentViewModel code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// // DocumentViewModel.swift // // Created by : Tomoaki Yagishita on 2020/11/05 // © 2020 SmallDeskSoftware // import Foundation import SwiftUI class DocumentViewModel: ObservableObject { // (1) @Binding var noteDoc: PackageDocSwiftUIDocument init(noteDoc: Binding<PackageDocSwiftUIDocument>){ self._noteDoc = noteDoc } // (2) var noteString: String { get { return noteDoc.noteString } set { noteDoc.noteString = newValue } } // (3) var image: UIImage? { get { if let image = noteDoc.image { return image } return UIImage(systemName: "nosign") } set { noteDoc.image = newValue } } } |
コード解説
- FileDocument プロトコルは、ドキュメントの Binding を提供してくれるので、Binding のまま保持するようにしています。
- 保持している文字列へのアクセサを提供しています。(特に何もしません)
- イメージへのアクセサ定義。ドキュメントが、image を保持していない時には、”nosign” のImage を代わりに返しています。
こうすることで、SwiftUI のビュー側で、nil 判定をなくすことができ、表示にフォーカスすることができるようになります。
View を作る
テキストとイメージを表示するだけですが、テキスト表示ビューの DocumentTextView とイメージ表示ビュー の DocumentImageView に分けてみました。
テキスト表示 DocumentTextView
TextEditor をそのまま Wrap して作りました。
DocumentTextView code
1 2 3 4 5 6 7 8 9 |
struct DocumentTextView: View { @Binding var text: String var body: some View { TextEditor(text: $text) .border(Color.gray) .ignoresSafeArea(.keyboard, edges: .all) } } |
イメージ表示 DocumentImageView
写真をクリックすると、UIImagePickerController を表示します。
そのために、拙作のライブラリを使っています。ライブラリは、こちら。
SwiftPM で git の URL を入力すれば使い始められます。
SwiftUIImagePickerController が色々としてくれるので、コードとしてはシンプルになりました。
DocumentImageView code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
struct DocumentImageView: View { // (1) @Binding var image: UIImage? @State private var metaData:NSDictionary? = nil @State private var showPhotoPicker = false var body: some View { Image(uiImage: image!) .resizable() .scaledToFit() .border(Color.gray) .onTapGesture { // (2) showPhotoPicker.toggle() } .fullScreenCover(isPresented: $showPhotoPicker) { // (3) SwiftUIImagePickerController(image: $image, metaData: $metaData, showCameraView: $showPhotoPicker) } } } |
コード解説
- SwiftUIImagePickerController で必要とする変数を定義しています。metaData は、選択された写真のメタデータですが、今回は使っていません
- イメージをタップされた時に、SwiftUIImagePickerController を表示します
- SwiftUIImagePickerController を表示します
ContentView
DocumentTextView と DocumentImageView を表示し、ViewModel を保持する ContentView は、以下のようになります。
ContentView code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct ContentView: View { @ObservedObject var viewModel: DocumentViewModel var body: some View { VStack { DocumentTextView(text: $viewModel.noteString) .frame(width: UIScreen.main.bounds.width, height: 200) DocumentImageView(image: $viewModel.image) .frame(width: UIScreen.main.bounds.width, height: 200) } } } |
# frame の大きさは、適当に決めてます。
App
最後に、DocumentGroup が ContentView に制御を渡す App を説明します。
MVVM で作りたかったので、少し強引に、ViewModel を作って渡しています。
PackageDocSwiftUIApp code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// // PackageDocSwiftUIApp.swift // // Created by : Tomoaki Yagishita on 2020/11/05 // © 2020 SmallDeskSoftware // import SwiftUI @main struct PackageDocSwiftUIApp: App { var body: some Scene { DocumentGroup(newDocument: PackageDocSwiftUIDocument()) { file in // (1) let viewModel = DocumentViewModel(noteDoc: file.$document) // (2) ContentView(viewModel: viewModel) } } } |
コード解説
- file は、FileDocumentConfiguration<Document> というタイプですが、保持している Document から、ViewModel を作っています
- Document から作成した ViewModel を、ContentView に渡しています。View からは、ViewModel 経由で Model(Document)へアクセスします。
作成したアプリ動作
作成したアプリは以下のように動作します。
まとめ: Package Document を使う iOS アプリの設定
Package Document を使う iOS アプリの設定
- Document Type, Exported Type IDを設定する
- UTType も定義し、FileDocument#readableContentTypes に設定する
- FileDocument#init で、読み込み用の FileWrapper を設定する
- FileDocument#fileWrapper で、保存用の FileWrapper を設定する
- DocumentGroup は、FileDocumentConfiguration<Document>を渡すので、Document から ViewModel を作って、ドキュメント表示用の View (ContentView) に渡す
- FileDocument は、Document への Binding を提供してくれるので、うまく使う
説明は以上です。 Happy Coding!
Sponsor Link