Display Large Collection of Images in UITableView with SDWebImage

Loading 1 or 3 images from server side into UITableView might not be a very challenging task. But when it comes to loading 50 or 100 images into a table view or collection view then things start becoming a little more complex. Especially when  user starts scrolling table view up and down very quickly. 

When we deal with a large collection of images loading into a table view it is very important to make sure out app remains to be responsive and images are not loaded multiple times from server thus generating lots of data traffic for user. This means we need to take of things like: 

  • Loading images from a remote server asynchronously,
  • Make sure that the same image won’t be downloaded several times,
  • Make sure that bogus URLs won’t be retried again and again,
  • See to it that application does not run out of memory and does not crash,
  • Make sure that application main thread is not blocked and our app remains responsive to user actions,
  • Execute block of code when image loading is done.

The good news is that this functionality is very common and has been implemented again and again by many other developers. SDWebImage is of the open source projects that does the a great job of handling asynchronous image downloading and memory + disk image caching with automatic cache expiration. If your application works with lots of images using SDWebImage will make things a lot easier for you and will help you speed up development time a great deal. 

In this video tutorial I am going to share with you how to load a large collection of images from a server side using Swift and how to display those images in a table view with SDWebImage. To break it down a bit more, we are going to learn:

  • How to build UITableView and implement UITableViewDatasource protocol,
  • How to create a custom UITableViewCell,
  • How to send HTTP GET request to load list of images in a form of JSON Array of JSON Objects,
  • Learn how to convert JSON Array into NSArray,
  • How to set image placeholder (no-image) into UIImageView while the target image is still loading,
  • How to integrate open source project SDWebImage done in Objective C into our Swift project,
  • How to asynchronously load images from server side URL,
  • How to add UIActivityIndicatorView and make it stop animating once images are loaded,
  • How to asynchronously execute code when image loading or retrieval is completed.

 Lots of value in one little tutorial :). Below is step by step video,  source code and links to other blog posts of mine with similar functionality. 

 

//
//  ViewController.swift
//  ImageLoadAndCacheDemo
//
//  Created by Sergey Kargopolov on 2016-05-28.
//  Copyright © 2016 Sergey Kargopolov. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var myTableView: UITableView!
    var imageCollection = [String]()
    let myActivityIndicator = UIActivityIndicatorView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        
        myActivityIndicator.center = self.view.center
        myActivityIndicator.hidesWhenStopped = true
        myActivityIndicator.activityIndicatorViewStyle = .Gray
        self.view.addSubview(myActivityIndicator)
        myActivityIndicator.startAnimating()
        
        loadImages()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return imageCollection.count
    }
 
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let myCell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! MyCustomTableViewCell
        
        //myCell.myImageView.image = UIImage(named: "no_image-128")
        
        let remoteImageUrlString = imageCollection[indexPath.row]
        let imageUrl = NSURL(string:remoteImageUrlString)
        
        let myBlock: SDWebImageCompletionBlock! = {(image: UIImage!, error: NSError!, cacheType: SDImageCacheType!, imageURL: NSURL!) -> Void in
           
            print("Image with url \(imageURL.absoluteString) is loaded")
            
        }
        
        //myCell.myImageView.sd_setImageWithURL(imageUrl, completed: myBlock)
        myCell.myImageView.sd_setImageWithURL(imageUrl, placeholderImage: UIImage(named: "no_image-128"), options: SDWebImageOptions.ProgressiveDownload, completed: myBlock)
        
        return myCell
    }
    
    func loadImages()
    {
        // Define server side script URL
        let scriptUrl = "https://www.swiftdeveloperblog.com/dynamic-list-of-images/"
        
        // Add one parameter
        let urlWithParams = scriptUrl + "?count=100"
        
        // Create NSURL Ibject
        let myUrl = NSURL(string: urlWithParams);
        
        // Creaste URL Request
        let request = NSMutableURLRequest(URL:myUrl!);
        
        // Set request HTTP method to GET. It could be POST as well
        request.HTTPMethod = "GET"
        
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in
            
            // Check for error
            if error != nil
            {
                print("error=\(error)")
                return
            }
            
            do {
                
            if let convertedJsonIntoArray = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSArray {
                
                for imageItem in convertedJsonIntoArray as! [[String:String]]  {
                    self.imageCollection.append(imageItem["thumb"]!)
                }
 
                 dispatch_async(dispatch_get_main_queue()) {
                    self.myTableView.reloadData()
                    self.myActivityIndicator.stopAnimating()
                 }
                
              }
                
            } catch let error as NSError {
               print(error.localizedDescription)
            }
            
            
            
        }
        
        task.resume()
    }


}

I hope this blog post is of some value to you. Please check these other blog posts of mine that deal with UIImageView and UITableView.

UIScrollView Programmatically Add UIImageView as SubView. Example in Swift.

Circular Image or Image with Rounded Corners. Example in Swift

Image Upload with Progress Bar example in Swift

Image upload example with Swift and PHP