# When to use built-in, 3rd party or a custom implementation for Async Image Loading in SwiftUI

In this blog post I reflect on the various options to have async image loading in SwiftUI:

- built-in option with `AsyncImage`
- reusing open-source projects (e.g. `SDWebImageSwiftUI`) 
- implement a custom solution

I'll share my personal experiences and recommendations on when to use what.

# SwiftUI's built-in option

SwiftUI on iOS 15 has `AsyncImage` that allows us to load images from the network. 

```Swift
AsyncImage(url: URL(string: "https://example.com/icon.png")) { image in
    image.resizable()
} placeholder: {
    ProgressView()
}
.frame(width: 50, height: 50)
```

[Apple Documentation](https://developer.apple.com/documentation/swiftui/asyncimage)

The obvious drawback is that **iOS 15+ is required**. Other things to consider are:
- no caching (other than what’s already offered by `URLSession`)
- only works with a `URL` (rather than also accepting a `URLRequest`)
- does not support animated images (GIF).

# Open-source projects

These three popular open-source projects do offer SwiftUI views and underlying image loading capabilities:

- [SDWebImageSwiftUI](https://github.com/SDWebImage/SDWebImageSwiftUI)
- [url-image](https://github.com/dmytro-anokhin/url-image) by [@dmytroanokhin](https://twitter.com/dmytroanokhin)
- [NukeUI](https://github.com/kean/NukeUI) by [Alex Grebenyuk](https://twitter.com/a_grebenyuk)

All three projects are published under the MIT license.

![Screen Shot 2022-02-03 at 6.25.54 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643898400052/2c4a4bYhZ.png)

![Screen Shot 2022-02-03 at 6.25.21 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643898426252/bptQE7rJr.png)

![Screen Shot 2022-02-03 at 6.25.40 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1643898414628/9bRJ89yIT.png)

In one of my projects I started with `url-image` but I switched to `SDWebImageSwiftUI` because I needed support for animated images.

Here are some stats (as of Feb 3rd 2022) to compare:

||SDWebImageSwiftUI|url-image|NukeUI|
|---|---|---|---|
|GitHub Stars|~ 1.3k|~ 930|~360|
|Last Release|March 2021 (2.0.2)|May 2021 (3.0.0)|January 2022 (0.8.0)|
|Supports Animated Images|Yes|No|Yes|
|iOS support|v13|v12|v12|
|macOS support|v10_15|v10_13|v10_14|
|watchOS support|v6|v4|v5|
|tvOS support|v13|v12|v12|
|Distribution|SPM, CocoaPods, Carthage|SPM|SPM, CocoaPods

# Custom implementation

Do you wan to go with a custom implementation? Read [Using Swift’s async/await to build an image loader](https://www.donnywals.com/using-swifts-async-await-to-build-an-image-loader/) from [Donny Walls](https://twitter.com/DonnyWals) to learn how to do that. It features the use of modern Swift concurrency (async/await)

Here's what the SwiftUI view's implementation could look like:

```Swift
struct RemoteImage: View {
    private let source: URLRequest
    @State private var image: UIImage?

    @Environment(\.imageLoader) private var imageLoader

    init(source: URL) {
        self.init(source: URLRequest(url: source))
    }

    init(source: URLRequest) {
        self.source = source
    }

    var body: some View {
        Group {
            if let image = image {
                Image(uiImage: image)
            } else {
                Rectangle()
                    .background(Color.red)
            }
        }
        .task {
            await loadImage(at: source)
        }
    }

    func loadImage(at source: URLRequest) async {
        do {
            image = try await imageLoader.fetch(source)
        } catch {
            print(error)
        }
    }
}
```

# Recommendation

If your app or framework supports iOS 15+ and you don't need advanced caching capabilities or animated images, go ahead with `AsyncImage` from SwiftUI.

Otherwise look at one of the open-source projects mentioned in this blog post.

If you have very particular requirements and you want/need to avoid external dependencies, you might want to try to build your own image loader. Personally I would try to avoid this as much as possible.



