UIToolbar CRUD

Korey Hinton Blog

Just copy and paste this in

Lately, whenever I'm learning a new technology I start by learning CRUD (Create, Read, Update, and Delete) for that technology. I start with a Playground and type it all out programmatically, then I copy and paste it into a project and fix any display issues I didn't foresee. Finally, I put the view items into a storyboard. For my reference and yours I'm posting the working programmatic version. Whenever I need this in the future I can come back to this and answer all of my how-tos for each CRUD case.

To get started create a new Single View project and swap out all the code in the ViewController.swift file with this:

import UIKit

class ViewController : UIViewController {

    var toolbar : UIToolbar!

    override func viewDidLoad() {
        super.viewDidLoad()

        /*** CREATE ***/

        toolbar = UIToolbar()
        toolbar.items = [
            UIBarButtonItem(title: "Read", style: UIBarButtonItemStyle.Plain, target: self, action: "readAction:"),
            UIBarButtonItem(title: "Update", style: UIBarButtonItemStyle.Plain, target: self, action: "updateAction:"),
            UIBarButtonItem(title: "Delete", style: UIBarButtonItemStyle.Plain, target: self, action: "deleteAction:")
        ]
        self.view.addSubview(toolbar)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // bounds is now correctly set
        toolbar.frame = CGRectMake(0, view.bounds.height-44, view.bounds.width, 44)
    }

    func readAction(sender: UIBarButtonItem) {

        /*** READ ***/

        println(sender.title)
        //        println(toolbar.items?.first?.title)
    }

    func updateAction(sender: UIBarButtonItem) {

        /*** UPDATE ***/

        sender.title = "Updated"
        //        toolbar.items[1].title = "Updated"
    }

    func deleteAction(sender: UIBarButtonItem) {

        /*** DELETE ***/

        toolbar.items?.removeLast()
        //        toolbar.items?.removeAtIndex(2)
    }


}

Code Explanation

Setting frame in viewDidLayoutSubviews method

If you've done a lot of programmatic frame positioning before you probably already know that the view's bounds are not properly set in the viewDidLoad method. The bounds values appear to be what the bounds would be like in portrait mode so your code will not look correct in landscape. Furthermore, without auto layout constraints we need it to update on screen rotation so we need to do it in a place that will be called after the view is loaded and bounds correctly set but also everytime the screen rotates. Luckily, viewDidLayoutSubviews does just this.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // bounds is now correctly set, feel free to now set frames

}

The commented out code

With UIBarButtonItem's target-action we get sent the UIBarButtonItem itself so reading and updating it is a cinch. I've added additional ways to access it off of the toolber object: toolbar.items and commented that out. You probably don't want a hard-coded index. In the deleteAction: function we cannot easily lookup an index of an item to use toolbar.items?.removeObjectAtIndex(..) because Swift arrays don't currently have a built-in way to do this like in Objective-C so you'd have to implement your own method to find the object or iterate. If necessary another option could be to tag the index of each item when it gets added to the array with the index it was inserted at. This way you can have the index of the one to delete: toolbar.items?.removeAtIndex(sender.tag)

Not using self or semicolons

I can't say whether this is best practice or not but I personally find Swift code to be more readable when I ommit self where it is not necessary to be explicit and also ommitting semicolons. I also find myself trying to stay from long variable and function names.

Storyboards

If you aren't a fan of storyboards this might be the type of control where you don't gain much by putting it in the storyboard. Many times you are going to want to have the UIToolbar either be at the top or bottom of its containing view. For cases like that our one line of code in viewDidLayoutSubviews takes care of it without needing to add auto layout constraints.

toolbar.frame = CGRectMake(0, view.bounds.height-44, view.bounds.width, 44)

Visual Picture

So the benefit you'll get from putting UIToolbar in a storyboard is that you can visually see the UIBarButtonItems and what it looks like without having to launch the device. To update a title or image you don't have to hunt through code, you can visually see what you need to change and what it looks like when you change it without having to run the app.

More CRUD

I like learning UIKit controls by figuring out the Create, Read, Update, Delete functionalities. So stay tuned for more articles like this one. Also, check out my UIScrollView CRUD article. Thanks!

Date: 2014-12-27T15:09+0000

Author: Korey Hinton

Org version 7.9.3f with Emacs version 24

Validate XHTML 1.0