iOS Swift Tutorial iOS8 PicInspire Xcode App Design

Swift iOS Tutorial: Taming UITableView Visual Blur and autolayout

This is the part 2 of Swift iOS Tutorial series :  Building a Photography inspiration app if you haven’t looked at the part 1 I strongly suggest you to complete that part before continuing.In the previous post we have successfully converted the json into a domain specific model like Photo. Instead of dealing with json directly we will be using the photo model in our view controllers.UITableView is one of the versatile class which can be used in many different usecases. We will be using UITableView to display a list of Photos in our application along with the exif data associated with the Photo.

Lets get started with our app in Xcode 6.

  • Delete the existing viewcontroller on the mainstory board and drag a uitableview controller from the object
    library on to the mainstory board.
    images
  • Create a PhotoListController class which is a subclass of UITableViewController.
  • Create a PhotoCell class which will be a subclass of UITableViewCell.
  • Select the PhotoListController and in the identity inspector set the class as PhotoListController.
    images
  • Similarly select the PhotoCell and set the class as PhotoCell.
  • Next step is customizing the PhotoCell.
    • Drag a imageview
    • Drag a visual blur view on top of imageview at the bottom.
    • Drag multiple uilable for each of the camera, iso, shutterspeed etc.
    • Select the element and arrange them approximately how you want them to be laid out.

Autolayout Constraints.

The next section of the blog deals with how to setup the autolayout constraints for individual elements. If you prefer watching a video here is the link

images
images
images
images
images
images
images
images

 

Creating the IBoutlets

Once you have the autolayout constraints setup properly. Open the mainstory board select the PhotoCell and CTRL+DRAG from all the labels, imageView and the visual blur onto the PhotoCell.swift

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

import UIKit

class PhotoCell: UITableViewCell {

    @IBOutlet weak var posterImageView: UIImageView!
    
    @IBOutlet weak var camera: UILabel!
    @IBOutlet weak var blurView: UIVisualEffectView!
    
    @IBOutlet weak var shutterSpeed: UILabel!
    @IBOutlet weak var iso: UILabel!
    @IBOutlet weak var lens: UILabel!

    @IBOutlet weak var focalLength: UILabel!
    override func awakeFromNib() {
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

}

PhotoListController

PhotoListController.swift is mostly boilerplate UITableView code which will setup the numerOfRowsInSection and the cellForRowAtIndexPath correctly.

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

import UIKit

class PhotoListController: UITableViewController {
    let manager : PhotoManager = PhotoManager()
    var photos: [Photo]!
    override func viewDidLoad() {
        super.viewDidLoad()

        manager.getPhotos(["tag":"sunset","only":"Nature","image_size":"4","rpp":"100"], completion: { (photos, error) -> () in
            self.photos = photos
            self.tableView.reloadData()
            for photo in photos {
                println("\(photo.name!)")
                println("\(photo.lens)")
                println("\(photo.shutterSpeed)")
                println("\(photo.camera)")
                println("\(photo.focalLength)")
                println("\(photo.iso)")
            }

        })
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1;
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let tphotos = self.photos{
            return tphotos.count;
        }
        return 0;
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("PhotoCell", forIndexPath: indexPath) as PhotoCell
        cell.posterImageView.image = nil;
        let photo = self.photos[indexPath.row]
        cell.camera.text = photo.camera
        cell.lens.text = photo.lens
        cell.shutterSpeed.text = photo.shutterSpeed
        cell.iso.text = photo.iso
        cell.focalLength.text = photo.focalLength
         /* AFNetworking extension for loading images async */
        cell.posterImageView.setImageWithURL(NSURL(string: photo.imageurl!));
        return cell
    }

}

About the author

Shrikar

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

  • Angel

    Hi Shrikar,

    Thank you for your awesome blog post! I went through it quite quickly and easily but I hit one major snag at the end with AFNetworking and the UIImageView. I’m having problems with this line:

    /* AFNetworking extension for loading images async */
    cell.posterImageView.setImageWithURL(NSURL(string: photo.imageurl!));

    The error reads that “‘UIImageView’ does not have member ‘setImageWithURL'”. However, I added AFNetworking on my Podfile (below) and under UIImageView+AFNetworking, there is a function for this. I don’t understand why this is failing for me though.
    I’ve looked on stackoverflow and some other blogs. Some suggest using Alamofire but i want to try using AFNetworking because it is ideal for this job; others suggest using a Swift version of UIImageView+AFNetworking library (Doesn’t work for me either).
    Could you help me with this?
    Thank so much.

    Podfile:
    platform :ios, ‘8.0’
    use_frameworks!

    target ‘Inspired’ do
    pod ‘SwiftyJSON’, ‘~> 2.2.0′
    pod ‘AFNetworking’, ‘~> 2.5′
    pod ‘Alamofire’, ‘~> 1.2′
    end

    • https://shrikar.com shrikar

      Did you create the bridging header and include “UIImageView+AFNetworking.h” ?

      • Angel

        Oh no! I didn’t. Darn… haha

        Would I only need to add #import “UIImageView+AFNetworking.h” to the bridging header file?

        Sorry, would you mind explaining why I need to do this? I’ve only created a header file maybe once before (I am relatively new to iOS).
        Thank you for responding so quickly!

        • https://shrikar.com shrikar

          Ok here is the deal. If you are including any objective C frameworks in your Swift app. You need to include all the necessary header files in the bridging header file.

          • Angel

            Thank you for explaining about bridging headers.
            Oh! I realized that I also needed to set the Objective-C bridging header with the path to the header file.

            Now that it builds…. None of the images are showing. Hm.. Any thoughts on where to look?

            Also, I have a question about the controllers: In the view controller, you wrote the code “manager.getPhotos([“only”:”Landscapes”, “image_size”:”4″]…” and in the photoListController, “manager.getPhotos([“tag”:”sunset”,”only”:”Nature”,”image_size”:”4″,”rpp”:”100″] ….”

            Was the params for getPhotos in ViewController supposed to be more general than that for the photoListController?

          • https://shrikar.com shrikar

            Yes may be I am not using the parameter.. But check if you are actually getting the images in the manager. Then you can isolate the issue.

          • Angel

            The app is crashing now. But the images from the manage are outputting correctly in the console. However there aren’t any images in the cells.

            I changed the output of numberOfSectionsInTableView to be 0 and left everything else as is. Seems like when I change it from 0 to 1, the app crashes.

/* ]]> */