【Xcode13】SwiftUIに追加される新機能-AsyncImageが便利!

Swift

少し前になりますが、WWDC21ではSwiftUIの新しい機能がたくさん紹介されていました。その中から今回は AsyncImage について説明していきます。XCode13以降、iOS15以降でしか使えないので、まだまだ業務などで使用はされないでしょうけど…。

いつも通り、Appleの公式ドキュメントを参考にしています。

AsyncImageとは

AsyncImageは画像を表示するビューです。指定したURLから画像を非同期で読み込んで表示することができます。

struct AsyncImage<Content> where Content : View

こんなふうに使用します。

struct ContentView: View {
    var body: some View {
        VStack{
            AsyncImage(url: URL(string: "https://example.com/icon.png"))
                .frame(width: 200, height: 200)
        }
    }
}

これだけで画像を取得でき次第表示してくれます。

placeholder が便利

さらにAsyncImageには以下のようなイニシャライザーがあります。

init<I, P>(url: URL?, scale: CGFloat = 1, content: @escaping (Image) -> I, placeholder: @escaping () -> P) where Content == _ConditionalContent<I, P>, I : View, P : View

これを使うと画像をロードしている間は別の画像などのView表示できます。ローディングのインジケーターを表示するのが一般的な使い方になるかと思います。

struct ContentView: View {
    var body: some View {
        VStack{
            AsyncImage(url: URL(string: "https://example.com/icon.png")){ image in
                image.resizable()
            } placeholder: {
                ProgressView()
            }
            .frame(width: 50, height: 50)
        }
    }
}

↑のように実装することで、ロード中はProgressViewを表示しておけます。

注意点

resizableなどの画像固有のモディファイアをAsyncImageに適用することはできません。そういったモディファイアを画像に適用したい場合は、上記のようにコンテンツクロージャーが取得するImageインスタンスに適用させる必要があります。

ロード失敗時の処理は?

ロードプロセスをより細かく制御したい場合は、AsyncImagePhaseを受信できるイニシャライザーを使いましょう。

init(url: URL?, scale: CGFloat = 1, transaction: Transaction = Transaction(), content: @escaping (AsyncImagePhase) -> Content)
これは、AsyncImagePhaseを受信して​​ロード操作の状態を示すコンテンツクロージャーを取得し、適したビューを返すことができます。
struct ContentView: View {
    var body: some View {
        VStack{
            AsyncImage(url: URL(string: "https://example.com/icon.png")) { phase in
                if let image = phase.image {
                    image
                } else if phase.error != nil {
                    Text("load error")
                } else {
                    ProgressView()
                }
            }
            .frame(width: 50, height: 50)
        }
    }
}

このように実装すれば、ロード中はプログレスビューを表示、ロード完了したら画像を表示、ロードに失敗したら「load error」と表示することができます。

めちゃめちゃ便利!

コメント