Open2

SwiftUI: .fileExporterを使う

kabeyakabeya

iOSにApple標準の「ファイル」appというのがあります。Finderみたいなものでしょうか。
ファイルを開いたり移動したりができます。

自前のAppからファイルを保存する際に、保存先を指定するのに「macOSならNSSavePanelのようなものを使いますが、iOSではUIDocumentPickerViewControllerを使います」のような説明を見ることがあります。

で、これがiOS14以降、SwiftUIでは.fileExporterという修飾子で同じ機能を使えるようになっているということだったので使ってみました。UIDocumentPickerViewController. fileExporterで、「ファイル」appを起動するようなイメージになります。イメージピッカーもiOS14ぐらいだったかに別アプリになったのと同様、セキュリティ/プライバシー管理が強化された一環なんでしょうね。

で、結論から言うと「保存先の指定というのとはかなり違う。エクスポートあるいは保存、というよりは、すでに保存してあるファイルを移動するのに使用する」ということのようです。NSSavePanelは保存先の指定のイメージですが、UIDocumentPickerViewController.fileExporterは移動です。そもそも全然違うんですね。

「移動」のイメージであるがゆえに.fileExporterを使うと以下のようになります。

  1. .fileExporter(isPresented:document:contentType:completionHandler:)document:は、ビューの構築時に評価される。なので、ここにファイルの生成処理を書いていると、エクスポート画面が表示されるタイミングではなく、呼び出し元のビュー構築時にファイルが生成される。ファイル生成自体が時間のかかる処理だと、呼び出し元ビューがなかなか表示されないということもあり得る。
  2. エクスポート画面のボタン名は「保存」ではなく「移動」(英語環境では「Save」ではなく「Move」)となる。これは変更できない。

1に関しては(これから試しますが)isPresented:のフラグをONに変える直前のタイミングでファイルの中身を生成するようにしたらいいのかなと考えています。
2はもうどうしようもなさそうです。「保存」に見せかけたい、というデベロッパからの要望も多そうな気はするのですが…

kabeyakabeya

1に関しては(これから試しますが)isPresented:のフラグをONに変える直前のタイミングでファイルの中身を生成するようにしたらいいのかなと考えています。

これで良さそうでした。

FileDocumentプロトコルのfileWrapper(configuration:)の呼び出し時に、実際のファイルの中身を生成して返せば良いので、ビュー構築時の.fileExporterのところではファイルの中身を生成しないようにします。