はじめに
この記事は、ObservableObject
を使って非同期に画像をダウンロードする方法を紹介します。
List表示時などに使うと便利だと思います。
TIPSとして活用してもらえたらと思います。
作り方
Step1.準備
画像を用意します。今回は、いらすとやの画像を活用させていただきます。
スマートフォンを使うペンギンのイラスト
https://www.irasutoya.com/2019/07/blog-post_4.html
画像のURLはhttps://1.bp.blogspot.com/-_CVATibRMZQ/XQjt4fzUmjI/AAAAAAABTNY/nprVPKTfsHcihF4py1KrLfIqioNc_c41gCLcBGAs/s400/animal_chara_smartphone_penguin.png
でした。
Step2.非同期で画像をダウンロードする
ObservableObjectを活用して、データを取得します。
バッググラウンドスレッドで画像を読み込み、@Published
した変数に格納するときはメインスレッドで更新します。
(Data Flow Through SwiftUI20:05あたりのスライド87ページより)
import Foundation
class ImageDownloader : ObservableObject {
@Published var downloadData: Data? = nil
func downloadImage(url: String) {
guard let imageURL = URL(string: url) else { return }
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
DispatchQueue.main.async {
self.downloadData = data
}
}
}
}
Step3. SwiftUIで扱えるUIパーツを作る
ObservableObjectを使い、画像読み込み終わるとUIImageを使い表示します。
読み込み中の場合は、ランアップできないので今回はSF Symbolの画像を表示します。
SF Symbolの画像以外に任意の画像に置き換えればいいと思います。
import SwiftUI
struct URLImage: View {
let url: String
@ObservedObject private var imageDownloader = ImageDownloader()
init(url: String) {
self.url = url
self.imageDownloader.downloadImage(url: self.url)
}
var body: some View {
if let imageData = self.imageDownloader.downloadData {
let img = UIImage(data: imageData)
return VStack {
Image(uiImage: img!).resizable()
}
} else {
return VStack {
Image(uiImage: UIImage(systemName: "icloud.and.arrow.down")!).resizable()
}
}
}
}
Step4.SwiftUIから読み込む
Step3で作成したURLImageをSwiftUIから呼び出します。
画像のURLを引数に呼び出すと自動で画像ダウンロードされたら表示されるようになります。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
URLImage(url: "https://1.bp.blogspot.com/-_CVATibRMZQ/XQjt4fzUmjI/AAAAAAABTNY/nprVPKTfsHcihF4py1KrLfIqioNc_c41gCLcBGAs/s400/animal_chara_smartphone_penguin.png")
.aspectRatio(contentMode: .fit)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}