Search code examples
iosswiftuiimagensurl

Loading/Downloading image from URL on Swift


I'd like to load an image from a URL in my application, so I first tried with Objective-C and it worked, however, with Swift, I've a compilation error:

'imageWithData' is unavailable: use object construction 'UIImage(data:)'

My function:

@IBOutlet var imageView : UIImageView

override func viewDidLoad() {
    super.viewDidLoad()
    
    var url:NSURL = NSURL.URLWithString("http://myURL/ios8.png")
    var data:NSData = NSData.dataWithContentsOfURL(url, options: nil, error: nil)

    imageView.image = UIImage.imageWithData(data)// Error here
}

In Objective-C:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *url = [NSURL URLWithString:(@"http://myURL/ios8.png")];
    NSData *data = [NSData dataWithContentsOfURL:url];

    _imageView.image = [UIImage imageWithData: data];
    _labelURL.text = @"http://www.urltest.fr/assets/img/iOS%20icon's%20Style/ios8.png";
 }

Can someone please explain me why the imageWithData: doesn't work with Swift, and how can I solve the problem.


Solution

  • Xcode 8 or later • Swift 3 or later

    Synchronously:

    if let filePath = Bundle.main.path(forResource: "imageName", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath) {
        imageView.contentMode = .scaleAspectFit
        imageView.image = image
    }
    

    Asynchronously:

    Create a method with a completion handler to get the image data from your url

    func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
        URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
    }
    

    Create a method to download the image (start the task)

    func downloadImage(from url: URL) {
        print("Download Started")
        getData(from: url) { data, response, error in
            guard let data = data, error == nil else { return }
            print(response?.suggestedFilename ?? url.lastPathComponent)
            print("Download Finished")
            // always update the UI from the main thread
            DispatchQueue.main.async() { [weak self] in
                self?.imageView.image = UIImage(data: data)
            }
        }
    }
    

    Usage:

    override func viewDidLoad() {
        super.viewDidLoad()
        print("Begin of code")
        let url = URL(string: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")! 
        downloadImage(from: url)
        print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
    }
    

    Extension:

    extension UIImageView {
        func downloaded(from url: URL, contentMode mode: ContentMode = .scaleAspectFit) {
            contentMode = mode
            URLSession.shared.dataTask(with: url) { data, response, error in
                guard
                    let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                    let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                    let data = data, error == nil,
                    let image = UIImage(data: data)
                    else { return }
                DispatchQueue.main.async() { [weak self] in
                    self?.image = image
                }
            }.resume()
        }
        func downloaded(from link: String, contentMode mode: ContentMode = .scaleAspectFit) { 
            guard let url = URL(string: link) else { return }
            downloaded(from: url, contentMode: mode)
        }
    }
    

    Usage:

    imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")