LoginSignup
22

More than 3 years have passed since last update.

SwiftUIで非同期で画像を表示する方法

Last updated at Posted at 2019-12-23

はじめに

この記事は、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ページより)

ImageDownloader.swift
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の画像以外に任意の画像に置き換えればいいと思います。

URLImage.swift
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を引数に呼び出すと自動で画像ダウンロードされたら表示されるようになります。

ContentView.swift
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()
    }
}

参考サイト

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22