0

I'm using this code to load an image from a URL: Loading/Downloading image from URL on Swift. That is working fine.

I've take the code out of the viewcontroller and put it into a class. Now the image only loads when I step through the code. I'm guessing this has something to do with the code running fine but everything finishes executing before the image has completely downloaded from the web.

What piece of this am I missing so the code waits for the image without holding up any other code executing in the viewcontroller?

class MyClass:NSObject {

private var myImage:UIImage = UIImage()

func getMyImage() -> UIImage {
    if let url = URL(string: self.myUrl) {
            self.myImage = self.downloadImage(url: url)
    }
    return self.myImage
}

func getDataFromUrl(url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url) { data, response, error in
        completion(data, response, error)
        }.resume()
}

func downloadImage(url: URL) {
    print("Download Started")
    getDataFromUrl(url: url) { data, response, error in
        guard let data = data, error == nil else { return }
        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() {
            self.myImage = UIImage(data: data)!
        }
    }
}
}

//in ViewController

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    DispatchQueue.main.async() {
        self.theImageView.image = self.myClass?.getImage()
    }
}
4thSpace
  • 43,672
  • 97
  • 296
  • 475

1 Answers1

1

You have to set up the imageView's image once the asynchronous call back is completed.

class MyClass: NSObject {
    // async function
    func getMyImage(completion: @escaping (UIImage?) -> Void) {
        // if the url is not available, completion with null
        guard let url = URL(string: self.myUrl) else { 
            completion(nil)
            return 
        }

        getDataFromUrl(url: url) { data, response, error in
            // if something goes wrong, completion with null
            guard let data = data, error == nil else { 
                completion(nil)
                return 
            }
            print(response?.suggestedFilename ?? url.lastPathComponent)
            print("Download Finished")
            completion(UIImage(data: data)!)
        }
    }
}

// in ViewController
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    getImage { image in 
        // async function will get called when image is ready
        DispatchQueue.main.async() { // set up your view in main thread
            self.theImageView.image = image
        }
    }
}
Willjay
  • 6,381
  • 4
  • 33
  • 58