Home » Swift » Swift async load image

Swift async load image

Posted by: admin November 30, 2017 Leave a comment

Questions:

I am working on show image from url async. I have tried to create a new thread for download image and then refresh on main thread.

func asyncLoadImg(product:Product,imageView:UIImageView){
    let downloadQueue = dispatch_queue_create("com.myApp.processdownload", nil)
    dispatch_async(downloadQueue){
        let data = NSData(contentsOfURL: NSURL(string: product.productImage)!)
        var image:UIImage?
        if data != nil{
            image = UIImage(data: data!)
        }
        dispatch_async(dispatch_get_main_queue()){
            imageView.image = image
        }

    }
}

When I was trying to debug that, when it comes to dispatch_async(downloadQueue), it jumps out the func. Any suggestion? Thx

Answers:

Swift 3 Updated Code :

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

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

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

        }).resume()
    }}

Swift 2.2 Code :

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

            NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: { (data, response, error) -> Void in

                if error != nil {
                    print(error)
                    return
                }
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    let image = UIImage(data: data!)
                    self.image = image
                })

            }).resume()
        }}

Now wherever you required just do this to load image from server url :

UIImageView.imageFromServerURL(“here server url”) .

Simple !

Questions:
Answers:

Use extension in Swift3. To resolve Network problem i recommend you use NSCache:

import UIKit

let imageCache = NSCache<NSString, AnyObject>()

extension UIImageView {
    func loadImageUsingCache(withUrl urlString : String) {
        let url = URL(string: urlString)
        self.image = nil

        // check cached image
        if let cachedImage = imageCache.object(forKey: urlString as NSString) as? UIImage {
            self.image = cachedImage
            return
        }

        // if not, download image from url
        URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
            if error != nil {
                print(error!)
                return
            }

            DispatchQueue.main.async {
                if let image = UIImage(data: data!) {
                    imageCache.setObject(image, forKey: urlString as NSString)
                    self.image = image
                }
            }

        }).resume()
    }
}

Hope it help!

Questions:
Answers:

Carrying on from Shobhakar Tiwari’s answer, I think its often helpful in these cases to have a default image in case of error, and for loading purposes, so I’ve updated it to include an optional default image:

Swift 3

extension UIImageView {
public func imageFromServerURL(urlString: String, defaultImage : String?) {
    if let di = defaultImage {
        self.image = UIImage(named: di)
    }

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

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

    }).resume()
  }
}

Questions:
Answers:

Here this code might help you.

   let cacheKey = indexPath.row
   if(self.imageCache?.objectForKey(cacheKey) != nil){
           cell.img.image = self.imageCache?.objectForKey(cacheKey) as? UIImage
    }else{
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
             if let url = NSURL(string: imgUrl) {
                  if let data = NSData(contentsOfURL: url) {
                            let image: UIImage = UIImage(data: data)!
                            self.imageCache?.setObject(image, forKey: cacheKey)
                            dispatch_async(dispatch_get_main_queue(), {
                                cell.img.image = image
                            })
                        }
                    }
                })
            }

With this image will download and cache without lagging the table view scroll

Questions:
Answers:

This solution make scrolling really fast without unnecessary image updates.
You have to add the url property to our cell class:

class OfferItemCell: UITableViewCell {
    @IBOutlet weak var itemImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel! 
    var imageUrl: String?
}

And add extension:

import Foundation
import UIKit

let imageCache = NSCache<AnyObject, AnyObject>()
let imageDownloadUtil: ImageDownloadUtil = ImageDownloadUtil()

extension OfferItemCell {
    func loadImageUsingCacheWithUrl(urlString: String  ) {
         self.itemImageView.image = nil
        if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
            self.itemImageView.image = cachedImage
            return
        }
        DispatchQueue.global(qos: .background).async {
            imageDownloadUtil.getImage(url: urlString, completion: {
                image in
                DispatchQueue.main.async {
                    if self.imageUrl == urlString{
                        imageCache.setObject(image, forKey: urlString as AnyObject)
                     self.itemImageView.image = image
                    }
                }
            })
        }
    }
}

You can also improve it and extract some code to a more general cell class i.e. CustomCellWithImage to make it more reusable.

Leave a Reply

Your email address will not be published. Required fields are marked *