iOS Swift Tutorial iOS8 PicInspire

Swift iOS Tutorial: Building a photography inspiration app – Part 1

If you have been following my blog posts you may know that we are going to build an app every month to learn new iOS concepts. You can find previous tutorials of Swift iOS Tutorial series here How to make an app.

This month we will be learning how to build a photography inspiration app. This app will help you learn / get new tricks by looking at the photos, the place where they took it and what kind of setting they used to get that photograph along with details like the camera used, lens used, shutter speed , aperture and more.

If you have some more awesome ideas/feature for this app. Please comment below.Here are a few things which we will learn in this app.

  • ) How to make an app interact with REST api’s.
  • ) Designing models in Swift.
  • ) More about UITableView and UICollectionview customization
  • ) Animations.

We will be using 500px data to search for certain keywords. To do that lets go ahead and create an app on 500px Developer page. Once you have the token you can test out certain sample REST api’s.

Example : If you want to search for photos in the landscape category and sort it by the highest rating and provide high res images with 100 photos per query we can perform a query like below.

https://api.500px.com/v1/photos/search?only=Landscapes&image_size=4&sort=highest_rating&rpp=100&consumer_key=you api key

You can run the query and find out what kind of data is returned.

Create a single view application and in the main storyboard select the view controller and set the view controller class to ViewController in the identity inspector.

At this point we will get into the model design. In our application we will deal with one main model object which will be our Photo Model.

//
//  Photo.swift
//  PicInspire
//
//  Created by Shrikar Archak on 3/1/15.
//  Copyright (c) 2015 Shrikar Archak. All rights reserved.
//

import Foundation
import SwiftyJSON
class Photo: NSObject {
    
    var name: String?
    var info: String?
    var camera: String?
    var lens: String?
    var focalLength: String?
    var iso: String?
    var shutterSpeed: String?
    var highest_rating: Double?
    var imageurl: String?
    init(data: JSON) {
        self.name = data["name"].stringValue
        self.info = data["description"].stringValue
        self.camera = data["camera"].stringValue
        self.lens = data["lens"].stringValue
        self.iso = data["iso"].stringValue
        self.focalLength = data["focal_length"].stringValue
        self.shutterSpeed = data["shutter_speed"].stringValue
        self.highest_rating = data["highest_rating"].doubleValue
        self.imageurl = data["images"][0]["url"].stringValue
    }
}

The model by it self is quite simple we have the name, info, camera , lens and many other parameters. Don’t worry about the initialization part for now, we will talk about that later. All you need to know is that the init function is passed a JSON object from which the object is initialized.

For dealing with networking operation we will be using Alamofire. We will also create a PhotoManager helper that will deal with all the rest api’s and convert the returned data into the model objects and return them. Alamofire or any other well designed library will be doing most of the work in async mode which means that even the functions of PhotoManager should be async. We can easily handle this in Swift using the closures. You can read more about swift closure here Swift Documentation
and Obj-C to Swift here.

//
//  PhotoManager.swift
//  PicInspire
//
//  Created by Shrikar Archak on 3/1/15.
//  Copyright (c) 2015 Shrikar Archak. All rights reserved.
//

import Foundation
import Alamofire
import SwiftyJSON

class PhotoManager: NSObject {
    let consumer_key = "kwCBBMQfMUkB1PjlNopdbTcqjzBrOv0hX20cQBQo"
    let baseurl = "https://api.500px.com/v1/photos/search"

    func getPhotos(var params: [String: String], completion : (photos : [Photo], error : NSError?)->()){

        params["consumer_key"] = consumer_key
        Alamofire.request(.GET, baseurl, parameters: params, encoding: ParameterEncoding.URL).responseJSON { (request, response, data , error) -> Void in
            let jsonData = JSON(data!)
            var photos : [Photo] = []
            for (_,photo) in jsonData["photos"] {
                let newphoto: Photo = Photo(data: photo)
                photos.append(newphoto)
            }
            return completion(photos: photos, error: error)
        }
    }
    
}

Lets look at the code in detail. We create a photomanager class and create some constants like consumer_key and the baseurl which are not going to change. The getPhotos function take in a set of params and pass it to the api endpoint which in our case is search. As you can see the second parameter is a closure which is passed to the getPhotos function and the same will be called when we receive the data from the REST api.

We add the consumer key to the api and make a request using the parameters passed in and the encoding type as URL encoded and return the response as a JSON String. At this point we will use the SwiftyJson to convert the json string to a jsonObject and extract the photos key from it. The photo object during the iteration phase is a tuple where in the photo.0 contains the index and the photo.1 contains the json representation of the data. We pass in the json object and initialize the photo object.

To test this sample out we will go ahead and add some code to the ViewController.swift

//
//  ViewController.swift
//  PicInspire
//
//  Created by Shrikar Archak on 2/11/15.
//  Copyright (c) 2015 Shrikar Archak. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    let manager : PhotoManager = PhotoManager()
    override func viewDidLoad() {
        super.viewDidLoad()

        manager.getPhotos(["only":"Landscapes","image_size":"4"], completion: { (photos, error) -> () in            
            for photo in photos {
                println("\(photo.name!)")
                println("\(photo.imageurl!)")
            }
        })
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

When you run this application you should be able to see a log of the name of the photo and the image url on the console. Now that we are done with the model design in the next tutorial we will get into designing and displaying the image and the necessary exif data.

Part 2 : Swift iOS Tutorial: Taming UITableView Visual Blur and Autolayout

About the author

Shrikar

Backend/Infrastructure Engineer by Day. iOS Developer for the rest of the time.

  • http://jasonwiener.com Jason Wiener

    great tutorial. FYI: in the PhotoManager the ‘->’ in the func declaration and the Alamofire calls are actually rendering as -> in the code blocks.

  • marcoryan

    Great BUT … the code does not compile in SWIFT 2> Issue seems to be in Photo Manager with the line:
    “func getPhotos( params: [String: String], completion: { (photos, error) -> ()”

    I am sure that it should not be “-&gt” new the end of the line, but what should it be?

/* ]]> */