Search code examples
swiftxcodexcode8alamofirealamofireimage

Retrieve and display multiple images from URL


Experimenting with Swift3, Alamofire and AlamofireImage. I am trying to display some Instagram images in a tableview. I have a data.json file of Places retrieved using Alamofire which look like this:

{
  "places" : [
    { "name" : "place1", "url" : "http://instagramImage1.jpg" },
    { "name" : "place2", "url" : "http://instagramImage2.jpg" },
    { "name" : "place3", "url" : "http://instagramImage3.jpg" },
  ]
}

I have setup PlaceTableViewCell with a UIImageView and attached it to an outlet in the corresponding controller.

I also have a PlaceTableViewController which includes:

var places = [Place]() //empty array to store places

In viewDidLoad() method I call a private function:

loadJson()

and the function looks like this:

private func loadJson() {
    Alamofire.request("https://example.com/data.json").responseJSON { response in
        if let JSON = response.result.value as? [String : Any],
            let places = JSON["places"] as? [[String : String]] {
            for place in places {
                //should I call loadImage() function here?
            }
        }
    }
}

I also have a model for each place in the JSON file:

import UIKit

class Place {

    var name: String
    var url: String

    init?(name: String, url: String) {
        self.name = name
        self.url = url     
    }

}

QUESTION

I'm not sure where to go from here. I would like to use AlamofireImage (which I have included in my project) to download each image but can I do this in a loop of some sort? I would also like to show each image in a new table row. Any advice and code examples would be much appreciated.


Solution

  • I would recommend not fetch the image in loadJSON.

    Why?

    • There could be a large number of photos coming back in the initial request, and the user may never even scroll down in the application far enough to see some of them.

    • On top of that, if you initialize too many requests simultaneously, some of the requests may time out while waiting for other requests to finish. So this is probably not the best solution.

    So, now coming to the solution. It makes sense to download the image data for only the cells that the user is attempting to view.

    TableView has a delegate method for this purpose only

    optional func tableView(_ tableView: UITableView, 
            willDisplay cell: UITableViewCell, 
               forRowAt indexPath: IndexPath)
    

    Use this method to load the images.

    extension ViewController: UITableViewDelegate {
       func tableView(_ tableView: UITableView, 
            willDisplay cell: UITableViewCell, 
               forRowAt indexPath: IndexPath) {
    
        let photoURL = places[indexPath.row].url
    
        // fetch this photo from web using URL
    
        // get the table view cell and update the image
         if let cell = self.tableView.cellForRow(at: indexPath) as UITableViewCell {
             cell.imageView.image = //fetchPhoto
         }   
        }
    }