Search photos on Flickr – Web Service

In this tutorial we will see the steps required to write a demo app that retrieves photos from Flickr based on search text and display them in a UICollectionView. This also covers how to integrate 3rd party libaries using CocoaPods.

Flickr API

Register your app in Flickr and get the API key details. You will need the API key to access the Flickr Photo Search API.

Project Setup

Create a new project by selecting Single View Application template and selecting language as Swift.

Install 3rd Party Libraries

We will be using CocoaPods to install third party libraries. First make sure to install CocoaPods on your Mac. Launch terminal window, navigate to the newly created project folder and create a file with name as Podfile. Edit the Podfile and add the following content

pod ‘Alamofire’
pod ‘SwiftyJSON’
pod ‘Haneke’

Alamorfire, SwiftyJSON and Haneke are the thirdparty libraries that will be used in this project. Alamofire for WebSerice call, SwiftJSON for parsing JSON data and Haneke for caching images.

After adiding the required libraries, type pod install on the terminal window. This should install the required libraries and create the necessary workspace. Now open <Project Name>.xcworkspace to add the functionality to the project.

Model Class

Add a new file (Photo.swift) to act as a place holder for storing photo details. Photo struct has properties for id, title, farm, secret, server and computed property which constructs the URL of the photo.

import UIKit

struct Photo {
    var id: String
    var title: String
    var farm: String
    var secret: String
    var server: String
    var imageURL: NSURL {
        get {
            let url = NSURL(string: "http://farm\(farm)\(server)/\(id)_\(secret)_m.jpg")!
            return url


Web Service Integration

Add new Swift file to the project and provide a name as Services.swift. Add the following code snippet to Services.swift

import Alamofire
import SwiftyJSON

protocol FlickrPhotoDownloadDelegate {
    func finishedDownloading(photos:[Photo])

class Services {

    let API_KEY = “"
    let URL = ""
    let METHOD = ""
    let FORMAT_TYPE:String = "json"
    let JSON_CALLBACK:Int = 1
    let PRIVACY_FILTER:Int = 1

    var delegate:FlickrPhotoDownloadDelegate?

    // MARK:- Service Call

    func makeServiceCall(searchText: String) {

        Alamofire.request(.GET, URL, parameters:  ["method": METHOD, "api_key": API_KEY, "tags":searchText,"privacy_filter":PRIVACY_FILTER, "format":FORMAT_TYPE, "nojsoncallback": JSON_CALLBACK])
           .responseJSON { (request, response, data, error) in
            if data != nil {
                let jsonData:JSON = JSON(data!)
                let photosDict = jsonData["photos"]
                let photoArray = photosDict["photo"]
                var photos = [Photo]()

                for item in photoArray  {
                    let id = item.1["id"].stringValue
                    let farm = item.1["farm"].stringValue
                    let server = item.1["server"].stringValue
                    let secret = item.1["secret"].stringValue
                    let title = item.1["title"].stringValue
                    let photo = Photo(id:id, title:title, farm:farm, secret: secret, server: server)
            } else {


The above code does the following

  • Makes a web service call to the flickr photo search API using Alamofire third party library.
  • Web Service results are parsed using SwiftyJSON library. 
  • The delegates are notified about the completion of the download by pasisng the photos array.

Design User Intrerfaces

Navigate to Main.storyboard, add a UICollectionView and UISearchBar to the ViewController as shown in the below screenshot.

Make sure add Auto Layout constriants so that the UI looks good for both iPad and iPhone. If you need help with Auto Layout then check out this tutorial.

As shown in the above screenshot, you need to add UIImageView to the CollectionViewCell. Now embed this ViewController inside Navigation Controller using the Editor -> Embed In -> Navigation Controller menu option.

Add another second View Controller to the Storyboard which would act as the Detail View Controller for displaying selected Photo.

Add Custom Cell

Create a new file (PhotoCell.swift) by selecting CocoaTouch class and keeping the base class as UICollectionViewCell. Set this class as the Custom Class for UICollectionViewCell in the Interface builder. Then create IBOutlet for the imageView in PhotoCell.

import UIKit

class PhotoCell: UICollectionViewCell {

    @IBOutlet weak var imageView: UIImageView!



Add PhotosViewController


You can rename the existing ViewController.swift to PhotosViewController.swift file. In the storyboard, select the ViewController with CollectionView and set the custom class name to PhotosViewController.

Create IBOutlets for UISearchBar and UICollectionView in PhotosViewController.

@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var collectionView: UICollectionView!

Implement the SearchBar delegate method and service call for searching photos based on the entered Search Text.

// MARK:- SearchButton

    func searchBarSearchButtonClicked(searchBar: UISearchBar) {
        searchBar .resignFirstResponder()

    // MARK:- SearchPhotos

    func searchForPhotos() {

Also add the following code snippet that processes the downloaded photos returned from the web service call. All UI calls needs to be done in the main thread hence setting the photos instance variable and update CollectionView are done within dispatch_async(dispatch_get_main_queue()).

// MARK:- Flickr Photo Download
    func finishedDownloading(photos: [Photo]) {
        dispatch_async(dispatch_get_main_queue(), { () -&gt; Void in
   = photos

Set the all the delegates and default value for the search bar in viewDidLoad method.

override func viewDidLoad() {

        collectionView.dataSource = self
        searchBar.delegate = self
        collectionView.delegate = self
        service.delegate = self

        // default
        searchBar.text = "famous quotes"

Add CollectionViewDataSource methods

In the PhotosViewController add the CollecitonViewDataSource methods for displaying the photos. This can be done by adding an extension to the PhotosViewController class.

extension PhotosViewController: UICollectionViewDataSource {
    // MARK:- UICollectionViewDataSource methods

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int {
        return 1

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
        return photos.count

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
        var cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoCell
        let photo = photos[indexPath.row]
        cell.imageView.frame.size = cell.frame.size
        return cell

    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        let photo:Photo? = photos[indexPath.row]
        if let photo = photo {
            let detailViewController = storyboard?.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
   = photo
            presentViewController(detailViewController, animated: true, completion: nil)

The cellForItemAtIndexPath uses the custom cell (PhotoCell) for displaying the Photo. Also uses the thirdparty library Haneke to load the imageView. And in the didSelectItemAtIndexPath method add the code for calling the DetailViewController by passwing the selecting photo.

Finally in the PhotosViewController add the code that calcuates the Cell Size to be displayed on the CollecitonView. This is done by implementing the UICollectionViewDelegateFlowLayout method.

extension PhotosViewController: UICollectionViewDelegateFlowLayout {
    // MARK:- UICollectioViewDelegateFlowLayout methods

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -&gt; CGSize
        let length = (UIScreen.mainScreen().bounds.width-15)/4
        return CGSizeMake(length,length);

Check out this article in stackoverflow for calculating the size of the CollectionViewCell.

Add DetailViewController

Add a new CocoaTouch class of Subclass as UIViewController with name as DetailViewController. Then add the following code to the class file.

import UIKit
import Haneke

class DetailViewController: UIViewController {

    var photo:Photo?
    var imageView:UIImageView?

    override func viewDidLoad() {

        if let photo = photo {

            imageView = UIImageView(frame: CGRectMake(0, 0, 320, 320))

            let tapGestureRecogonizer = UITapGestureRecognizer(target: self, action: Selector("close"))

    override func didReceiveMemoryWarning() {

    // MARK:- viewDidLayoutSubviews

    override func viewDidLayoutSubviews() {

        let size = view.bounds.size
        let imageSize = CGSizeMake(size.width,size.width)
        imageView?.frame = CGRectMake(0.0, (size.height - imageSize.height)/2.0, imageSize.width, imageSize.height)

    // MARK:- close
    func close() {
        dismissViewControllerAnimated(true, completion: nil)

The above code does the following

  • Calculates the size of the imageview and aligns it to the centre of the ViewController.
  • Loads the image using the third party library Haneke.
  • Adds a gesture recogonizer that dismisses the ViewContorller on tap gesture.

Dowload the source code from here.

In Category: Swift, UICollectionView, WebService, Xcode

Ravi Shankar

A polyglot software developer and now exploring Swift and iOS development. If you would like to learn from me then check out services page.

Show 1 Comment
  • praveen April 9, 2016, 12:05 pm

    I encounter this error while try to launch the app,

    The operation couldn’t be completed. (LaunchServicesError error 0.)

Leave a Comment