Codementor Events

AsyncImage. Loading images in SwiftUI

Published Jun 08, 2021
AsyncImage. Loading images in SwiftUI

Note: Examples are tested on iOS 15.0 with Xcode 13.0 beta (13A5154h).

iOS 15.0 beta gives us new SwiftUI views, and one of them is AsyncImage. It loads and displays an image from the given URL.

Let's start with a basic example:

import SwiftUI

struct ContentView: View {

    private let url = URL(string: "https://picsum.photos/200")

    var body: some View {
        AsyncImage(url: url)
    }
}

By default, it shows a gray background and replaces it with the loaded image:
Group 1-2.png
Empty and success states of AsyncImage

Optionally we can change scale to use for the image. In the example below the image size will be reduced by half:

import SwiftUI

struct ContentView: View {

    private let url = URL(string: "https://picsum.photos/200")

    var body: some View {
        AsyncImage(url: url, scale: 2)
    }
}

To update the appearance of AsyncImage, we can use an initializer with content and placeholder view builders. Here we able to modify a final image and show a custom placeholder view:

import SwiftUI

struct ContentView: View {

    private let url = URL(string: "https://picsum.photos/200")

    var body: some View {
        AsyncImage(url: url) { image in
            image
                .resizable()
                .aspectRatio(contentMode: .fit)
        } placeholder: {
            Image(systemName: "photo")
                .imageScale(.large)
                .foregroundColor(.gray)
        }
        .ignoresSafeArea()
    }
}

Group 2.png
Custom placeholder and resized image

If we want to handle an error state, we can use another initializer with AsyncImagePhase. It's a simple enum with three cases: empty, success, and error.

import SwiftUI

struct ContentView: View {

    private let url = URL(string: "https://picsum.photos/200")

    var body: some View {
        AsyncImage(url: url, content: view)
    }

    @ViewBuilder
    private func view(for phase: AsyncImagePhase) -> some View {
        switch phase {
        case .empty:
            ProgressView()
        case .success(let image):
            image
                .resizable()
                .aspectRatio(contentMode: .fit)
        case .failure(let error):
            VStack(spacing: 16) {
                Image(systemName: "xmark.octagon.fill")
                    .foregroundColor(.red)
                Text(error.localizedDescription)
                    .multilineTextAlignment(.center)
            }
        @unknown default:
            Text("Unknown")
                .foregroundColor(.gray)
        }
    }
}

Here we show a spinner during loading, resized image if loading is successful, and an error message if something is wrong.
4d8da70c-138c-4caa-98ce-ccb9bd219d07.png
Working with phases of AsyncImage

To specify animations between phase changes, we can optionally add Transition:

import SwiftUI

struct ContentView: View {

    private let url = URL(string: "https://picsum.photos/200")
    private let transaction: Transaction = .init(animation: .linear)

    var body: some View {
        AsyncImage(url: url,
                   transaction: transaction,
                   content: view)
    }
    ...
}

And, of course, we can use AsyncImage inside List to show multiple images:

import SwiftUI

struct ContentView: View {

    private let url = URL(string: "https://picsum.photos/200")

    var body: some View {
        List {
            ForEach(0..<10) { _ in
                AsyncImage(url: url,
                           content: view)
                    .listRowInsets(.init(.zero))
            }
        }
        .listStyle(.plain)
    }
    ...
}

*Finally, we can show List without separators *

If you want to play with AsyncImage by yourself, check out AsyncImageExample project on Github.

References

Twitter · Telegram · Github

Discover and read more posts from Artem Novichkov
get started
post comments1Reply
Quintan Barnes
a year ago

“AsyncImage: Loading images in SwiftUI” is an informative blog post that sheds light on the efficient loading of images in SwiftUI. The use of AsyncImage allows for seamless and smooth image loading, enhancing the user experience. The visuals at https://depositphotos.com/stock-photos/gas-fireplace.html beautifully illustrate the potential applications, such as displaying captivating gas fireplace images. This blog is a valuable resource for SwiftUI developers seeking to optimize image loading and create visually stunning apps.