📌

【SwiftUI】AsyncImageにオートリロードを実装する

2023/12/03に公開

非同期で画像を取得中に画面遷移を行った場合、画像の取得はキャンセルされます。遷移先から遷移元に戻ってきた時に画像の取得を再開してくれれば便利なのですが、残念ながらAsyncImageにそのような機能はありません。そのため自分自身でオートリロードを実装する必要があります。

下記のコードでは独自で定義したAutoReloadableAsyncImageを再帰的に呼び出すことで、この悩みを解決しています。実際に試してみたい方はシミュレータでアプリを立ち上げた後、なるべく早く5回ほど遷移してみると分かりやすいと思います。

struct ContentView: View {
    private let viewNum: Int
    private let imageURL = URL(string: "https://picsum.photos/4500/3000")

    init(viewNum: Int = 1) {
        self.viewNum = viewNum
    }

    var body: some View {
        NavigationStack {
            Text("Here is View\(viewNum).")
                .bold()

            AutoReloadableAsyncImage(imageURL: imageURL)
                .frame(height: 300)

            NavigationLink("Next") {
                ContentView(viewNum: viewNum + 1)
            }
        }
        .font(.title2)
    }
}


struct AutoReloadableAsyncImage: View {
    let imageURL: URL?

    var body: some View {
        AsyncImage(
            url: imageURL,
            transaction: .init(animation: .easeIn(duration: 0.6))
        ) { phase in
            switch phase {
            case .empty:
                ProgressView()
            case .success(let image):
                image
                    .resizable()
                    .scaledToFit()
            case .failure(let error):
                if error.localizedDescription == "cancelled" {
                    AutoReloadableAsyncImage(imageURL: imageURL)
#if DEBUG
                        .task { print("reloaded") }
#endif
                } else {
                    Text(error.localizedDescription)
#if DEBUG
                        .task { print(error.localizedDescription) }
#endif
                }
            @unknown default:
                EmptyView()
            }
        }
    }
}

https://www.youtube.com/watch?v=RcSi94-DNwk&list=TLPQMDMxMjIwMjMydYN3R0o3hQ&index=1

Discussion