AboutContact

UICollectionView image gallery: download and display images inside the cell

In this Swift 2 tutorial you'll see how to use an UICollectionView as an image gallery. You'll see how to download the images in an asynchronous way, how to properly cache them for the current session, to avoid to download them again while scrolling the UICollectionView, and finally how to display them inside the custom Cell.

Project initialization

Let's create a new iOS Swift single view application. For this tutorial we'll use the http protocol, for this reason we need to allow it inside the info.plist swift file. Let's right click on it, choose open as, choose source code and inside it add the NSAppTransportSecuity key and enable the NSAllowsArbitraryLoads. This will allow your iOS App to use the http protocol.

<key>NSAppTransportSecurity</key>

<dict>

	<key>NSAllowsArbitraryLoads</key>

	<true/>

</dict>

Layout definition

Open now the main.storyboard. We'll add inside the UIViewController an UICollectionView and then we'll customize the cell inside it. Under the file inspector we can disable the use size classes feature, we don't need that.

Add inside the UIViewController the CollectionView, set the size to fit the screen size, and add the following constraints for the top, left, right and bottom.

Swift add contraints to uicollectionview

 

Select now the cell of the UICollectionView, under the size inspector change size to Custom and add a width and height of 120. This parameter is not used by swift when is rendering the cell on the iOS App, but allows us just to define better the custom cell.

Choose the UIImageView component and put it inside the UiCollectionViewCell. Align it and resize it inside the cell as you want and at the constraints. Here are the contraints I've used:

swift: add contraint to the image view

Create the Custom cell Class

In order to have a custom cell, we need also a custom class. Let's create it.

Choose File - New - File

Select iOS - Cocoa Touch Class

For subclass choose UICollectionViewCell

And for class choose the name you want, we will use in this case CellClass

Press next and create

Swift: create new class

Turn now back to the main.storyboard and select the UICollectionView Cell.

Under the identity inspector write the class name you've previously created (CellClass in my case) and  under the attribute inspector write "cell" as an identifier (or write the name you want).

Swift reusable cell

 

Link with the assistant editor the image view to the custom class

Now it's time to link the UIImageView to the custom class (CellClass). Select the UIImageView, open the Assistant Editor (it's on the right top, the two circles), hold CTRL key button and drag and drop the UIImage inside the Cell Class.

 

Select now the UICollectionView and using the Assistant Editor link it to the ViewController class. As a variable name I wrote collectionview, but be free to put the name you want.

Download the images and display them inside the cells

It's now time to download the images and to display them inside the cells. Open the ViewController.swift class.

Define now the required data structures.

The images cache array allows to keep for the current session (for all the time the app is opened) the downloaded images in a cache, this allows to avoid to download them again while scrolling. In fact every time the user scrolls the CollectionView, the cells are reused. Reusing a cell is something like destroying the previous content and display the new one. So we'll keep for this reason the content stored.

The image array allows us to  keep the json data structure that defines the links of the images.

The link String defines the link of the json of the images. In this example I've prepared for you a simple array of images.

You can find it here.

var images_cache = [String:UIImage]()
var images = [String]()
let link = "https://www.kaleidosblog.com/tutorial/get_images.php"

For getting the links of the images, we'll use the json format. Let's define the functions for downloading and parsing the data.

The get_json is used to download from the link the json array of images, the extract_json_data perform the data extraction from the json string, and load image is a function that requires as an input the link of the image and the UIImageView of the cell. In this ImageView the image will be displayed as soon as is arrived.

    func load_image(link:String, imageview:UIImageView)
    {
        
        let url:NSURL = NSURL(string: link)!
        let session = NSURLSession.sharedSession()
        
        let request = NSMutableURLRequest(URL: url)
        request.timeoutInterval = 10

        
        let task = session.dataTaskWithRequest(request) {
            (
            let data, let response, let error) in
            
            guard let _:NSData = data, let _:NSURLResponse = response  where error == nil else {
                
                return
            }
                
 
            var image = UIImage(data: data!)
            
            if (image != nil)
            {
                
                
                func set_image()
                {
                    self.images_cache[link] = image
                    imageview.image = image
                }
  
                
                dispatch_async(dispatch_get_main_queue(), set_image)
                
            }
            
        }
        
        task.resume()
        
    }

    


    func extract_json_data(data:NSString)
    {
        let jsonData:NSData = data.dataUsingEncoding(NSASCIIStringEncoding)!
        let json: AnyObject?
        
        do
        {
            json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
        }
        catch
        {
            print("error")
            return
        }
        
        guard let images_array = json! as? NSArray else
        {
            print("error")
            return
        }
        
        for var j = 0; j < images_array.count ; ++j
        {
            images.append(images_array[j] as! String)
        }
        
        dispatch_async(dispatch_get_main_queue(), refresh)
    }
    
    
    
    func refresh()
    {
        self.collectionview.reloadData()
    }
    

    func get_json()
    {
     
        let url:NSURL = NSURL(string: link)!
        let session = NSURLSession.sharedSession()
        
        let request = NSMutableURLRequest(URL: url)
        request.timeoutInterval = 10
        
        
        let task = session.dataTaskWithRequest(request) {
            (
            let data, let response, let error) in
            
            guard let _:NSData = data, let _:NSURLResponse = response  where error == nil else {
                
                return
            }
           
            let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)

            self.extract_json_data(dataString!)
            
        }
        
        task.resume()
        
    }

Finally let's initialize the cell's width and height, the UICollectionView data source class and delegate. Remember to implement for the ViewController class the UICollectionViewDataSource, UICollectionViewDelegate methods (just write them above  the ViewController class name definition, like ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate)

The numberOfItemsInSection method uses the images array to let Swift know how many cells are to display.

cellForItemAtIndexPath function defines the content of a single cell defined by indexPath row (the number of the cell).

Remeber to put as a dequeueReusableCellWithReuseIdentifier the reusable identifier that you wrote under the attribute inspector.

    override func viewDidLoad() {
        super.viewDidLoad()

        
        let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()

        layout.itemSize = CGSizeMake(120,120)
        
        
        self.collectionview.setCollectionViewLayout(layout, animated: true)
        
        get_json()
        
        collectionview.delegate = self
        collectionview.dataSource = self
    }

    
    
    internal func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        return images.count
    }
    

    internal func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
    {
        let cell:CellClass = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CellClass
        
        if (images_cache[images[indexPath.row]] != nil)
        {
            cell.Image.image = images_cache[images[indexPath.row]]
        }
        else
        {
            load_image(images[indexPath.row], imageview:cell.Image)
        }
        
        return cell
    }
    

    internal func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
    {
        return 1
    }
    

 

Complete project example download

Here you can download the final project

Here you can download the project for Swift 3


 

Leave a comment








Comments


- 26 May 2017 at 17:51
I am a immature developer and we have learned a lot from your tutorials but still at last I am facing a problem. I wish you could help me as my error is related to JSON and my app in not showing output in my collection view as your application was showing the output. I would be highly obliged if you could discuss with me the same so that i could learn some more from you.
- 28 April 2017 at 20:13
Hi, I got this error running the app: App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file. I did add the exception into the Info.plist as you instructed but found no luck. Seems like the issue's been around: https://github.com/NativeScript/nativescript-cli/issues/1666 Do you have a work around?
Andrea - 04 May 2017 at 12:15
Yes, from iOS 10 the NSAllowsArbitraryLoads is ignored. You'll have to allow the single domains that you use with the http protocol! Example
- 14 April 2017 at 17:26
Hi! Very useful post, thank you very much. Now, I'm trying to build a new view in which I could show one single image from this online gallery, but I'm having problems making the segue. Do you know how to perform it?
Andrea - 04 May 2017 at 12:18
You can do easily using the uicollection didselect event. Here you can access to the indexPath of the selected item, and push the navigation view with the image information (image name or image index), or just open a popup with the big image!
- 17 March 2017 at 12:57
can you please tell me the php code
Andrea - 18 March 2017 at 18:02
Hi, here it is: https://www.kaleidosblog.com/tutorial/get_images.txt
- 24 November 2016 at 04:28
Any chance you will be updating this for Swift 3? I tried following along, but there are a few pieces that are erroring out on me, and I can't quite figure out how to work around them.
Andrea - 24 November 2016 at 08:42
- 15 August 2016 at 18:22
Could you explain how to do this if the json data is a dictionary rather than array of strings? I need to pull the 'image name' field out of a dictionary and create an array of those items first, which doesn't work with your code...
Andrea - 01 September 2016 at 09:17
Hi, thank you for your comment! You have to extract and store into your array the elements of the json data you need. Have a look at this tutorial! https://www.kaleidosblog.com/swift-uitableview-load-data-from-json Hope it helps
- 13 August 2016 at 23:40
Hello. I've tried your code without json but with an array of strings URL from images from Parse.com I can say it works perfect. Although we could really hope to see an "NSCache" version of your example so the user's network dont download each time the images... Thanks a lot though your code is 100% working :)
Andrea - 01 September 2016 at 09:21
Hi! Thank you for your comment! Sure I'll write a new tutorial about it using the NSCache! Thank you again!
- 20 July 2016 at 02:02
Tried to load in Xcode * Beta 2 and Swift 3, And I get some errors I don't know how to handle?? Can you try this and perhaps repair?
- 15 July 2016 at 03:47
Greate tutorial man. Just a quick question. What happen if your image_cache is full? How can you reset/clear your image_cache? Thank you
Andrea - 15 July 2016 at 14:07
Hi, the images_cache is just a temporary array cache. This array is emptied as soon as the app is closed. This is helpful when you scroll down and up your list in order to avoid download images again. If you want a more permanent cache you have to store the images data. You can reset/clear this temporary cache just by emptying your array.
- 19 June 2016 at 05:53
hey man thank you for this tutorial well explained you should upload some videos to youtube as well.. keep the good work
Andrea - 22 June 2016 at 08:50
Thank you for your comment, soon I will post also some videos
- 12 April 2016 at 05:19
Hello, what is the PHP code? I've tried to use the script on my server but i have a problem with the PHP script. Can you post this? But anyway, very cool and helpful! Greets from germany
Andrea - 12 April 2016 at 21:49
Hi, thank you for your comment! Sure, here it is: https://www.kaleidosblog.com/tutorial/get_images.txt





AboutContactPrivacy