概要
SwiftUIの画像データをネットワークなどから取得して、描画する方法のメモ。
勘違いをしている箇所などありましたらぜひご指摘いただけると嬉しいです。
やりかた
ObservedObjectを使ってデータ更新を通知する
https://developer.apple.com/documentation/swiftui/state-and-data-flow
1.ObservableObject
を継承したデータモデルを作成
2.データ更新を受け取るViewのプロパティに1で作成したデータモデルを追加して@ObservedObject
をつける
3.1で作成したデータモデルにUIImageのプロパティを追加して、@Published
をつけておく
データモデル側
/// ObservableObjectを継承したデータモデルを作る
final class ImageContainer: ObservableObject {
// @PublishedをつけるとSwiftUIのViewへデータが更新されたことを通知してくれる
@Published var image = UIImage(systemName: "photo")!
init(from resource: URL) {
// ネットワークから画像データ取得
let session = URLSession(configuration: .default)
let task = session.dataTask(with: resource, completionHandler: { [weak self] data, _, _ in
guard let imageData = data,
let networkImage = UIImage(data: imageData) else {
return
}
DispatchQueue.main.async {
// 宣言時に@Publishedを付けているので、プロパティを更新すればView側に更新が通知される
self?.image = networkImage
}
session.invalidateAndCancel()
})
task.resume()
}
}
View側
struct ContentView: View {
// 監視対象にしたいデータに@ObservedObjectをつける。
@ObservedObject var container: ImageContainer
var body: some View {
Image(uiImage: container.image)
}
}
解説
※ こちらに記載されている内容を引用しながらやっていることを書いていきます。
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
モデルクラス(今回の例だとImageContainer)内のデータが変更された場合にSwiftUIに反映するには、モデルクラスがObservableObject
を継承する必要があります。
To make the data changes in your model visible to SwiftUI, adopt the ObservableObject protocol for model classes.
final class ImageContainer: ObservableObject { ... }
このモデルクラス内のプロパティに@Published
をつけることで、プロパティが更新されたときに通知をすることができます。
To publish a property, add the Published attribute to the property’s declaration:
final class ImageContainer: ObservableObject {
@Published var image: UIImage
}
この更新をSwiftUI側で監視するために@ObservableObject
のアノテーションをつけてプロパティを宣言します。
To tell SwiftUI to monitor an observable object, add the ObservedObject attribute to the property’s declaration
struct ContentView: View {
@ObservedObject var container: ImageContainer
}
ImageContainer
でネットワーク経由での画像の取得が完了しvar image: UIImage
が更新されることによって、
ImageContainer
を監視していたSwiftUI側に表示更新の通知がされます。
参考情報
こちらの記事もとても参考にさせていただきました。
https://qiita.com/shiz/items/6eaf87fa79499623306a