UICollectionView. Load List of Images From Remote Server Url

In this tutorial, you will learn how to load a list of images from a remote server URL in Swift. Also, you will learn about UICollectionView, background thread, and more.

By the end of this tutorial, you will have a working Swift code example that you can use in your mobile application.

Step 1: Create UICollectionView Programmatically

To create a UICollectionView programmatically, you’ll need to define its layout and properties. This involves setting up a UICollectionViewFlowLayout and assigning it to the collection view. You’ll also register a cell class or nib to use for the collection view’s cells.

If you are new to UICollectionView check this detailed guide about creating UICollectionView in Swift Programmatically.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
    layout.itemSize = CGSize(width: 60, height: 60)
    
    myCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    myCollectionView!.dataSource = self
    myCollectionView!.delegate = self
    myCollectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
    myCollectionView!.backgroundColor = UIColor.white
    self.view.addSubview(myCollectionView!)
    
    loadListOfImages()
}

Step 2: Implement UICollectionView Delegate Method

To handle taps on the collection view items, you need to implement the collectionView(_:didSelectItemAt:) delegate method. This method is called whenever a user taps on an item in the collection view.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    print("User tapped on item \(indexPath.row)")
    
    let imageDictionary = self.images[indexPath.row] as! NSDictionary
    let imageUrlString = imageDictionary.object(forKey: "url") as! String
    
    print("Image url = \(imageUrlString)")
}

Step 3: Load the list of images from a remote server

To load a list of images from a remote server, you’ll need to make an HTTP GET request. This is done using URLSession.shared.dataTask(with: request).

func loadListOfImages() {
    let scriptUrl = "https://jsonplaceholder.typicode.com/photos"
    let myUrl = URL(string: scriptUrl);
    var request = URLRequest(url:myUrl!)
    request.httpMethod = "GET"
    
    let task = URLSession.shared.dataTask(with: request) {
        data, response, error in
        
        if error != nil {
            print("error=\(String(describing: error))")
            return
        }
        
        do {
            if let convertedJsonIntoArray = try JSONSerialization.jsonObject(with: data!, options: []) as? NSArray {
                self.images = convertedJsonIntoArray as [AnyObject]
                DispatchQueue.main.async {
                    self.myCollectionView!.reloadData()
                }
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }
    }
    task.resume()
}

When you get a response back from the server it returns JSON. You need to convert this JSON to NSDictionary to show the image to your UI. Check this details guide on how to convert JSON string to NSDictionary in Swift.

Step 4: Create UIImageView

Inside the collectionView(_:cellForItemAt:) method, you create an UIImageView to display the image. This is done by creating a new UIImageView instance, setting its frame to match the cell’s size, and then adding it to the cell.

let imageView = UIImageView(frame: CGRect(x:0, y:0, width:myCell.frame.size.width, height:myCell.frame.size.height))

Step 5: Create UIImageData and Load Image from a Remote URL

To load an image from a remote URL, you first convert the URL to Data using NSData(contentsOf: imageUrl as URL). Then, you create a UIImage from this data.

DispatchQueue.global(qos: .userInitiated).async {
    let imageData:NSData = NSData(contentsOf: imageUrl as URL)!
    DispatchQueue.main.async {
        let image = UIImage(data: imageData as Data)
        imageView.image = image
        imageView.contentMode = UIView.ContentMode.scaleAspectFit
        myCell.addSubview(imageView)
    }
}

Notice the use of DispatchQueue.global. It helps to load image data in a background thread.

Loading images in a background thread ensures that the main application remains responsive. This is achieved by dispatching the image loading task to a global queue with a quality of service class and then updating the UI on the main queue.

DispatchQueue.global(qos: .userInitiated).async {
    // Load image data
    DispatchQueue.main.async {
        // Update UI
    }
}

To learn more about background threads check this tutorial on Time Consuming Task in Background Thread in Swift

Step 7: Add UIImageView as a Subview to UICollectionViewCell

Finally, you add the UIImageView as a subview to the UICollectionViewCell. This is done after the image has been loaded and the UI is updated on the main queue.

myCell.addSubview(imageView)

Complete Code Example

Here’s how all the steps come together in a complete example.

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    
    var images = [AnyObject]()
    var myCollectionView:UICollectionView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
        layout.itemSize = CGSize(width: 60, height: 60)
        
        myCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        myCollectionView!.dataSource = self
        myCollectionView!.delegate = self
        myCollectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
        myCollectionView!.backgroundColor = UIColor.white
        self.view.addSubview(myCollectionView!)
        
        loadListOfImages()
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.images.count
    }
    
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath as IndexPath)
        myCell.backgroundColor = UIColor.black
        
        let imageDictionary = self.images[indexPath.row] as! NSDictionary
        let imageUrlString = imageDictionary.object(forKey: "url") as! String
        let imageUrl:NSURL = NSURL(string: imageUrlString)!
        
        DispatchQueue.global(qos: .userInitiated).async {
            
            let imageData:NSData = NSData(contentsOf: imageUrl as URL)!
            
            DispatchQueue.main.async {
                let imageView = UIImageView(frame: CGRect(x:0, y:0, width:myCell.frame.size.width, height:myCell.frame.size.height))
                let image = UIImage(data: imageData as Data)
                imageView.image = image
                imageView.contentMode = UIView.ContentMode.scaleAspectFit
                
                myCell.addSubview(imageView)
            }
        }
        
        return myCell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
    {
        print("User tapped on item \(indexPath.row)")
        
        let imageDictionary = self.images[indexPath.row] as! NSDictionary
        let imageUrlString = imageDictionary.object(forKey: "url") as! String
        
        print("Image url = \(imageUrlString)")
    }
    
    
    func loadListOfImages()
    {
        // Send HTTP GET Request
        
        // Define server side script URL
        let scriptUrl = "https://jsonplaceholder.typicode.com/photos"
        
        // Create NSURL Ibject
        let myUrl = URL(string: scriptUrl);
        
        // Creaste URL Request
        var request = URLRequest(url:myUrl!)
        
        // Set request HTTP method to GET. It could be POST as well
        request.httpMethod = "GET"
        
        
        // Excute HTTP Request
        let task = URLSession.shared.dataTask(with: request) {
            data, response, error in
            
            // Check for error
            if error != nil
            {
                print("error=\(String(describing: error))")
                return
            }
            
            // Convert server json response to NSDictionary
            do {
                if let convertedJsonIntoArray = try JSONSerialization.jsonObject(with: data!, options: []) as? NSArray {
                    
                    self.images = convertedJsonIntoArray as [AnyObject]
                    
                    DispatchQueue.main.async {
                        self.myCollectionView!.reloadData()
                    }
                    
                }
            } catch let error as NSError {
                print(error.localizedDescription)
            }
            
        }
        
        task.resume()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
}

load-list-of-images-from-remote-server-url

Conclusion

I hope this tutorial was helpful for you. There are a lot more Swift code examples on this website if you check the  Swift Code Examples page.

Additionally, you might also want to check a list of recent Swift tutorials where you will also find a list of useful resources for iOS mobile app developers.

Leave a Reply

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