[swift3] Swift 3: Display Image from URL

In Swift 3, I am trying to capture an image from the internet, and have these lines of code:

var catPictureURL = NSURL(fileURLWithPath: "http://i.imgur.com/w5rkSIj.jpg")
var catPictureData = NSData(contentsOf: catPictureURL as URL) // nil
var catPicture = UIImage(data: catPictureData as! Data)

What am I doing wrong here?

This question is related to swift3

The answer is


The easiest way according to me will be using SDWebImage

Add this to your pod file

  pod 'SDWebImage', '~> 4.0'

Run pod install

Now import SDWebImage

      import SDWebImage

Now for setting image from url

    imageView.sd_setImage(with: URL(string: "http://www.domain/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))

It will show placeholder image but when image is downloaded it will show the image from url .Your app will never crash

This are the main feature of SDWebImage

Categories for UIImageView, UIButton, MKAnnotationView adding web image and cache management

An asynchronous image downloader

An asynchronous memory + disk image caching with automatic cache expiration handling

A background image decompression

A guarantee that the same URL won't be downloaded several times

A guarantee that bogus URLs won't be retried again and again

A guarantee that main thread will never be blocked Performances!

Use GCD and ARC

To know more https://github.com/rs/SDWebImage


Using Alamofire worked out for me on Swift 3:

Step 1:

Integrate using pods.

pod 'Alamofire', '~> 4.4'

pod 'AlamofireImage', '~> 3.3'

Step 2:

import AlamofireImage

import Alamofire

Step 3:

Alamofire.request("https://httpbin.org/image/png").responseImage { response in

if let image = response.result.value {
    print("image downloaded: \(image)")
self.myImageview.image = image
}
}

I use AlamofireImage it works fine for me for Loading url within ImageView, which also has Placeholder option.

func setImage (){

  let image = “https : //i.imgur.com/w5rkSIj.jpg”
  if let url = URL (string: image)
  {
    //Placeholder Image which was in your Local(Assets)
    let image = UIImage (named: “PlacehoderImageName”)
    imageViewName.af_setImage (withURL: url, placeholderImage: image)
  }

}

Note:- Dont forget to Add AlamofireImage in your Pod file as well as in Import Statment

Say Example,

pod 'AlamofireImage' within Your PodFile and in ViewController import AlamofireImage


Swift

Good solution to extend native functionality by extensions

import UIKit
    
extension UIImage {
  convenience init?(url: URL?) {
    guard let url = url else { return nil }
            
    do {
      self.init(data: try Data(contentsOf: url))
    } catch {
      print("Cannot load image from url: \(url) with error: \(error)")
      return nil
    }
  }
}

Usage

Convenience initializer is failable and accepts optional URL – approach is safe.

imageView.image = UIImage(url: URL(string: "some_url.png"))

Use extension for UIImageView to Load URL Images.

let imageCache = NSCache<NSString, UIImage>()

extension UIImageView {

    func imageURLLoad(url: URL) {

        DispatchQueue.global().async { [weak self] in
            func setImage(image:UIImage?) {
                DispatchQueue.main.async {
                    self?.image = image
                }
            }
            let urlToString = url.absoluteString as NSString
            if let cachedImage = imageCache.object(forKey: urlToString) {
                setImage(image: cachedImage)
            } else if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    imageCache.setObject(image, forKey: urlToString)
                    setImage(image: image)
                }
            }else {
                setImage(image: nil)
            }
        }
    }
}

let url = URL(string: "http://i.imgur.com/w5rkSIj.jpg")
let data = try? Data(contentsOf: url)

if let imageData = data {
    let image = UIImage(data: imageData)
}

You could also use Alamofire\AlmofireImage for that task: https://github.com/Alamofire/AlamofireImage

The code should look something like that (Based on the first example on link above):

import AlamofireImage

Alamofire.request("http://i.imgur.com/w5rkSIj.jpg").responseImage { response in
    if let catPicture = response.result.value {
        print("image downloaded: \(image)")
    }
}

While it is neat yet safe, you should consider if that worth the Pod overhead. If you are going to use more images and would like to add also filter and transiations I would consider using AlamofireImage


let url = ("https://firebasestorage.googleapis.com/v0/b/qualityaudit-678a4.appspot.com/o/profile_images%2FBFA28EDD-9E15-4CC3-9AF8-496B91E74A11.png?alt=media&token=b4518b07-2147-48e5-93fb-3de2b768412d")


self.myactivityindecator.startAnimating()

let urlString = url
    guard let url = URL(string: urlString) else { return }
    URLSession.shared.dataTask(with: url)


{
(data, response, error) in
        if error != nil {
            print("Failed fetching image:", error!)
            return
        }

        guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
            print("error")
            return
        }

        DispatchQueue.main.async {
            let image = UIImage(data: data!)
        let myimageview = UIImageView(image: image)
            print(myimageview)
            self.imgdata.image = myimageview.image
self.myactivityindecator.stopanimating()

     }
  }.resume()

Use this extension and download image faster.

extension UIImageView {
    public func imageFromURL(urlString: String) {

        let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
        activityIndicator.frame = CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
        activityIndicator.startAnimating()
        if self.image == nil{
            self.addSubview(activityIndicator)
        }

        URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in

            if error != nil {
                print(error ?? "No Error")
                return
            }
            DispatchQueue.main.async(execute: { () -> Void in
                let image = UIImage(data: data!)
                activityIndicator.removeFromSuperview()
                self.image = image
            })

        }).resume()
    }
}