Sponsor Link
環境&対象
- macOS14.5
- Xcode 15.4
- iOS 17.5
- Swift 5.9
ShareLink
SwiftUI には、共有メニューを作成するための 要素として、ShareLink という View が用意されています。
参考
ShareLinkApple Developer Documentation
以下のように使用します。item として渡しているものが、共有先に渡されるデータです。
struct ContentView: View {
var body: some View {
VStack {
ShareLink("hello", item: "Hello", preview: SharePreview("Hello"))
}
.padding()
}
}
以下の記事で説明しています。
[SwiftUI] ShareLink の使い方(その1)
ShareLink での item の評価タイミング
凝った使い方をしようかなぁと考えたときに、気づくことがあります。
item の評価タイミングです。
ShareLink に渡す item は、当然ながら、ShareLink という View が表示されるときに評価されます。
ShareLink を表示する View によっては、この制限が邪魔になることがあります。
ShareLink を表示するためには、その引数も評価することが必要ですので、言語仕様的には当然ですが、使用する側からすると、ShareLink の ボタンがクリックされた時点で、評価して欲しい時があります。
ShareLink の item 評価を遅延させたいケースの例
例えば、共有向けデータの生成に 多くの計算コストがかかる場合です。
ShareLink が表示されるたびに計算されるため、評価の計算量が大きい時には、このことが問題となりえます。
開発者視点では、ShareLink が表示されるタイミングではなく、実際に共有される時にのみ 評価して欲しくなります。
実際に評価タイミングを確認してみます。
import SwiftUI
import OSLog
extension OSLog {
fileprivate static var log = Logger(subsystem: "sharelinkEval", category: "timing")
}
final class ViewModel: ObservableObject {
@Published var config: Bool = false
func shareData() -> String {
OSLog.log.debug("shareData generated with big calculation.... with config:\(self.config)")
return "Hello \(config)"
}
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
Text("Hello, world!")
Toggle(isOn: $viewModel.config, label: { Text("Bool in ViewModel") })
ShareLink(item: viewModel.shareData())
}
.padding()
}
}
実行すると、以下のように ShareLink が 表示されます。
ShareLink が”表示された時” に、コンソールに以下のような表示が行われますので、item は、表示された時に評価されているとわかります。
shareData generated with big calculation.... with config:false
デフォルトでは、config は false なので、生成されている shareData の値に問題はありません。
この画面で、Toggle を操作すると、以下のように表示され、(ビューが更新されることによって)item も再評価されていることがわかります。
shareData generated with big calculation.... with config:true
ShareLink の item 評価を遅延させる方法
特に秘策があるわけではありません・・・
item が評価されてしまうのは、item として ShareLink に渡すために必要だからです。
そのため、(良くも悪くも) 表示のたびに item が評価されてしまいます。
表示するタイミングで評価をさせない方法の1つとしては、item の元データを Transferable にしてしまうことがあります。
ここの例では、ViewModel を Transferable にしてしまうということです。
そこにデータとして存在するものを item に渡すので、評価は発生しません。
実際に item に使用されるものは、Transferable に準拠させることで設定します。
extension ViewModel: Transferable {
static var transferRepresentation: some TransferRepresentation {
ProxyRepresentation(exporting: { viewModel in
return viewModel.shareData()
})
}
}
上記では、ViewModel を Transferable に準拠させ、渡すデータとしては、先ほど使用していたものと同じ shareData() としています。
実際の共有操作(ファイル保存等)が選択された時に、shareData が呼び出されることになります。
コンソールに表示されるログを確認することで、ShareLink が表示されたタイミングで shareData が計算されることはないことがわかります。
まとめ
ShareLink の item を遅延評価させる
- item は、ShareLink が表示される時に評価される
- item が transferable に準拠していれば実際に共有操作された時に transferRepresentation に従って評価される
- すでに、transferable に準拠している時は、transferRepresentation の定義順に気をつけないといけない
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
SwiftUI おすすめ本
SwiftUI を理解するには、以下の本がおすすめです。
SwiftUI ViewMatery
SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、便利です。
英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。
View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。
超便利です
販売元のページは、こちらです。
SwiftUI 徹底入門
# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。
Swift学習におすすめの本
詳解Swift
Swift の学習には、詳解 Swift という書籍が、おすすめです。
著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。
最新版を購入するのがおすすめです。
現時点では、上記の Swift 5 に対応した第5版が最新版です。
Sponsor Link