June 11, 2015

Project: Learn how to build Make School Notes!


Let's take a look at adding a search bar to our Dashboard Scene.

See if you can add a Search Bar object to your Dashboard Scene yourself.


Much like the table view, we will need a UISearchBar IBOutlet to connect our search object to our controller code and we will be creating yet another new extension to implement the search delegate UISearchBarDelegate.

We will then implement a state system into our NoteViewController for displaying notes normally (DefaultMode) and another state for what to display when we are utilizing search (SearchMode).

Let's add this outlet and possible search states.

Open NotesViewController. Change it to read as follows:

class NotesViewController: UIViewController {

  @IBOutlet weak var searchBar: UISearchBar!
  @IBOutlet weak var tableView: UITableView!

  enum State {
    case DefaultMode
    case SearchMode

  var state: State = .DefaultMode

Now time to tackle the interface.

  1. Connect your Search Bar in your interface to the searchBar outlet.
  2. Set the Search Bar Delegate. You can do this as you did before with tableView e.g. searchBar.delegate = self. However you can also do it by opening the Connections Inspector for the Search Bar object and dragging the delegate outlet to the Dashboard.


Let's add some search functionality. Realm can use NSPredicate to filter its result set. NSPredicate allows you to construct logical conditions used to constrain a search. It's easier to see it in action.

Add the following function to the NotesViewController class:

        func searchNotes(searchString: String) -> Results<Note>? {
            do {
                let realm = try Realm()
                let searchPredicate = NSPredicate(format: "title CONTAINS[c] %@ OR content CONTAINS[c] %@", searchString, searchString)
                return realm.objects(Note).filter(searchPredicate)
            } catch {
                print("realm error")
                return nil

Here's what this does: IF the TEXT entered in the search bar is found in either the TITLE or the CONTENT of a note, then include that matching note as part of the result set.

Search Delegate

Now we need our app to know when we are modifying our search bar. This is where the UISearchBarDelegate comes into play.

Add the following extension to the NotesViewController:

extension NotesViewController: UISearchBarDelegate {

  func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    state = .SearchMode

  func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    state = .DefaultMode

  func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    notes = searchNotes(searchText)


Run your app. Pretty nice, eh? Although the search works well, the user experience can always be better. Let's improve it:

The State Machine

When the Dashboard is presented we want to revert to .DefaultMode.

Ensure func viewWillAppear reads as follows:

    override func viewWillAppear(animated: Bool) {

        do {
            let realm = try Realm()
            notes = realm.objects(Note).sorted("modificationDate", ascending: false)
            state = .DefaultMode
        } catch {
            print("handle error")

We are setting the default state. However nothing will happen unless we use the ever-useful didSet functionality to perform actions when our state machine is updated.

Ensure your state variable definition reads as follows:

    var state: State = .DefaultMode {
        didSet {
            switch (state) {
            case .DefaultMode:
                do {
                    let realm = try Realm()
                    notes = realm.objects(Note).sorted("modificationDate", ascending: false) //1
                    self.navigationController!.setNavigationBarHidden(false, animated: true) //2
                    searchBar.resignFirstResponder() // 3
                    searchBar.text = ""
                    searchBar.showsCancelButton = false
                } catch {
                    print("realm error")
            case .SearchMode:
                let searchText = searchBar?.text ?? ""
                searchBar.setShowsCancelButton(true, animated: true) //4
                notes = searchNotes(searchText) //5
                self.navigationController!.setNavigationBarHidden(true, animated: true) //6

What's going on:

  1. We have moved our default state search code so whenever we return to default state the list is reset.
  2. This returns the navigation bar in an animated fashion - you can see why it was hidden in point 6.
  3. Remove keyboard popup.
  4. Animate in a cancel button beside the search bar. This just looks nice (UI Polish).
  5. Perform a search on any text entered into the search bar.
  6. This makes the search bar take p rominence in our view. By hiding the navigation bar the user is focused on search. (UI Polish)

Run the App


Find the bug!

Looks great! But if you play around a bit you may discover a pretty serious UX bug.

Try to find this bug and fix it by yourself. You can do it!

When you go into search mode, you hide the navigation bar. But if you tap on a note when you're in search mode, you never re-show the navigation bar; the only way to get back to the Dashboard is to delete the note! There are a few ways to fix this. One is to make sure the navigation bar is shown every time your NoteDisplayViewController appears. To do this, add the following to the viewWillAppear method in your NoteDisplayViewController:

self.navigationController!.setNavigationBarHidden(false, animated: true)

Finding and fixing bugs like this is great practice. No matter how well-thought-out your code is, some things will always slip through the cracks.

Well done! You have made it this far and have a fully functional Notes application.
Sure, it may not be super pretty and polished yet. However, it's your first app and a great starting place in your development.

The next chapter is a brief chapter on app polishing. We will look at changing the color of various elements to start putting your own stamp on it.


If you have feedback on this tutorial or find any mistakes, please open issues on the GitHub Repository.

Join Make School Icon

Join Make School

Prepare for your career as a founder or software developer

Apply now
Talk to Us Icon

Talk to Us

If you have any questions, please send us an email.

Email Us