WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

Cannot stop List from freezing when trying to load images

Forums > SwiftUI

In my app, I have a List which displays a view in each row, and these views try to download an image from the Internet. I am trying to stop the List from freezing while downloading the image. The app works great on a fast network, but I am having problems getting the download to happen in the background. I have tried using the .task(priority: .background) to load the image, but it does not work. I must not be understanding something, any help is appreciated. Here is my code for the view which needs to load the images. I have my downloading code in a shared object which the view calls. Not all of the items to display have the cover property so that it is why it is optional, and I display a default image if the cover is not present.

import SwiftUI
import CoreImage

struct CoverView: View {

    var cover: Int?
    var size: String
    var height: Double
    @State private var tempImage: UIImage?
    @State private var uiImage: UIImage?
    @State private var modifier1 = 0.62
    @State private var modifier2 = 1.0

    @EnvironmentObject var downLoader: BookDownloader

    var body: some View {

        Group {
            if cover != nil {

                if let uiImage = uiImage {
                    Image(uiImage: uiImage)
                        .resizable()
                        .frame(width: height * modifier1, height: height * modifier2)
                } else {
                    ProgressView()
                } 

            }
        }
        .onChange(of: tempImage, perform: { newValue in
            uiImage = tempImage
        })
        .task(priority: .background) {

            if let cover = cover {

                    if cover > 0 {

                            tempImage =  await downLoader.getUIImageForCover(cover: cover, size: size)

                    } else {
                        tempImage = UIImage(systemName: "x.circle")
                        modifier1 = 0.5
                        modifier2 = 0.5
                    }
            }
        }
    }
}

This is the networking code in the downLoader object:

func getUIImageForCover(cover: Int, size: String) async -> UIImage? {

            let urlString = getCoverImageURLString(cover: cover, size: size)

            return await getUIImageForURLString(url: urlString)

    }

  private func getUIImageForURLString(url: String) async -> UIImage? {

        do {

            guard let urlToDownload = URL(string: url) else {
                assert(true, "URL failed")
                return nil
            }

            let data = try Data(contentsOf: urlToDownload)

            // stores the data in the book struct so it can be saved into a BookData ultimately

            book?.coverImageData = data

            if let uiImage = UIImage(data: data) {
                return uiImage
            }

        } catch {
            print(error.localizedDescription)
        }

        return nil
    }

  private func getCoverImageURLString(cover: Int, size: String)  -> String {
        // checks to make sure the size string is of the right type

        assert(size == "S" || size == "M" || size == "L", "Wrong size entered into getCoverImageURLString")

        let urlString =  "https://covers.openlibrary.org/b/id/\(cover)-\(size).jpg"

        return urlString

    }

   

Have you tried using AsyncImage?

   

I have not tried that I will do so. For a larger question, is it better to download the image once and store locally, or is it better to download on demand which may impact performance. The images are relatively small but there are a lot of them.

   

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!

Read the book

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.