Best Practices, Tutorial Resources

Enumified TableView with Dynamic Prototype Cells in Swift

How I refactored my app’s Settings screen code to be much more flexible and readable, while unlocking a more complicated TableView at the same time! Win-Win!

I stumbled upon this amazing post by Frédéric Adda over at Nova Era called Structure Your UITableView Better with Structs and Enums in Swift as I was searching for a way to refactor the Settings page in my app, BB Links, to make it easier to add in new settings options anywhere, or change around any items/sections, without needing to manually worry about the section and row index numbers.

The linked post above explains how you can use enums and structs to replace the indexes for section and rows–it’s really cool!!! 😎 Exactly what I was looking for! Below is my implementation of it for my app’s Settings screen, and I took this concept even further later on in so I could easily have different Dynamic Prototype Cells! 😱

With this change, I can move any item to any section and change the order of sections and items all within a couple of seconds! To do that with section and row indexes requires a bunch of index changes which can get confusing to keep track of.

Here’s how I set it up in my app, first implementing the enums and structs, as Frédéric’s article suggested:

private enum SectionType {
  case Account
  case Other
}

private enum Item {
  case ManageAccounts
  case ActiveAccount
  case DefaultCountry
  case AboutMe
  case Donate
  case RateApp
  case ShareApp
}

private struct Section {
  var type: SectionType
  var items: [Item]
}

First, I created the SectionType enum which represents the different sections I want to have in the Settings screen. I have an Account section and Other.

Next, I create the Item enum which contains all of the different tableView rows I have in the Settings screen.

Lastly, a Section struct is created which is identified as containing a SectionType enum and an array of Item enums.

Once those three components were set up, the next step was to create an instance of an array of Section structs, which will hold the various sections in the Settings screen.

class SettingsViewController: UIViewController {
  private var sections = [Section]()
  ...
}

In the viewDidLoad() method, I assign the items that belong in each section:

override func viewDidLoad() {
  super.viewDidLoad()
  // Setup sections/rows for table
  sections = [
    Section(type: .Account, items: [.ManageAccounts, .ActiveAccount, .DefaultCountry]),
    Section(type: .Other, items: [.AboutMe, .Donate, .RateApp, .ShareApp])
  ]
  ...
}

The Account section contains the ManageAccounts, ActiveAccount and DefaultCountry tableview rows, and the Other section contains the remaining four rows.

Next up…the UITableViewDataSource implementation which I have as an extension to my SettingsViewController class.

// MARK: - UITableViewDataSource
extension SettingsViewController: UITableViewDataSource {
  func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return sections.count
  }

  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].items.count
  }

  func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch sections[section].type {
    case .Account:
      return "Account"
    case .Other:
      return nil
    }
  }
  ...
}

For tableView:numberOfSectionsInTableView:, you just return the count of your sections array, which will be 2 as it contains my two Section structs.

for tableView:numberOfRowsInSection:, return the count of items in each section, and for tableView:titleForHeaderInSection:, I setup a switch statement to switch through the types, returning the name for each section. (For Other, I just wanted it to be blank, so I didn’t return a title).

Before I show how I used these enums and structs to help me easily implement three different dynamic protoypes, here’s how I implemented the UITableViewDelegate methods:

// MARK: - UITableViewDelegate Methods
extension SettingsViewController: UITableViewDelegate {
  // Goes to product detail when cell tapped
  func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    switch sections[indexPath.section].items[indexPath.row] {
    case .ManageAccounts:
      performSegueWithIdentifier("ManageCoachIDs", sender: self)
    case .ActiveAccount:
      performSegueWithIdentifier("DefaultCoachID", sender: self)
    case .DefaultCountry:
      performSegueWithIdentifier("DefaultCustomerCountry", sender: self)
    case .AboutMe:
      performSegueWithIdentifier("About", sender: self)
    case .Donate:
      performSegueWithIdentifier("Donate", sender: self)
    case .RateApp:
      rateApp()
    case .ShareApp:
      shareAppFrom(indexPath)
    }
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
  }
}

I just switch between the section and row using the sections array, and perform my segues or functions for each Item. It’s all very clear what is what thanks to the Item enum setup earlier! I love it! ❤️ Without this setup, you’d just have combinations of sections and row index numbers and you’d need to keep track of which is which with comments. And don’t even think it would be simple to switch them around. With the way this is setup, it really doesn’t matter which order you put the case Items…it’s all handled by the way you place them in your section variable up in the viewDidLoad()! Brilliant! 🙌

For the final part, I’ll show how I easily implemented my three dynamic prototype cells, which are just a simple Basic Cell, a Subtitle Cell and Right Detail Cell (setup as such in the storyboard with appropriate cell identifiers):

Here’s how my storyboard is setup:

Storyboard

And implementation of tableView:cellforRowAtIndexPath::

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
  // Setup a cellIdentifer string to store the cell reuse identifier you want to use for each row.
  var cellIdentifier: String

  // Switch through each row and set the appropriate cell reuse identifier
  switch sections[indexPath.section].items[indexPath.row] {
  case .ManageAccounts, .AboutMe, .Donate:
    cellIdentifier = "BasicCell"
  case .RateApp, .ShareApp:
    cellIdentifier = "SubtitleCell"
  case .ActiveAccount, .DefaultCountry:
    cellIdentifier = "RightDetailCell"
  }

  // Populate your cell reuse identifier into the cell
  let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)

  // Switch through each cell, and implement the labels/setup for each row
  // The order of the cases is irrelevant!
  switch sections[indexPath.section].items[indexPath.row] {
  case .ManageAccounts:
    cell.textLabel?.text = "Manage Coach IDs"
  case .ActiveAccount:
    cell.textLabel?.text = "Active Coach ID"
    let coachID = dataModel.getActiveCoachID()
    if coachID != "" {
      cell.detailTextLabel?.text = coachID
    } else {
      cell.detailTextLabel?.text = ""
    }
  case .DefaultCountry:
    cell.textLabel?.text = "Default Country"
    cell.detailTextLabel?.text = dataModel.getDefaultCountry()
  case .AboutMe:
    cell.textLabel?.text = "About the Developer 💪🤓"
  case .Donate:
    cell.textLabel?.text = "☕️☕️☕️?"
  case .RateApp:
    cell.textLabel?.text = "Rate BB Links ⭐️⭐️⭐️⭐️⭐️"
    if let reviewCount = reviewCount {
      cell.detailTextLabel?.text = "\(reviewCount) people have rated this version"
      UIView.animateWithDuration(0.3, animations: {
        cell.detailTextLabel?.alpha = 1.0
      })
    } else {
      cell.detailTextLabel?.text = " "
      cell.detailTextLabel?.alpha = 0.0
    }
    cell.accessoryType = .None
  case .ShareApp:
    cell.textLabel?.text = "Share BB Links 🗣👥"
    cell.detailTextLabel?.text = "Know a coach who would love this app?"
    cell.accessoryType = .None
  }

  // Return the cell
  return cell
}

I love the way this worked because it’s clear exactly which row I’m working with, and I can quickly change the cell type by moving around the row Item where the cellIdentifier variable string is set in the first switch statement and changing its cell implementation details! So. Much. Clearer! 🙌

With all of this setup the way it is, adding new sections or rows is a cinch! I could totally rearrange this tableView to look completely different switching a couple of lines of code. The normal way would be way more difficult.

Here’s the finished result in-app:

Settings Screen Result

It’s now setup for quick modifications in the future! 🎉

If you ask me, enumified tableViews with dynamic prototype cells rock! 😎

Standard
Tutorial Resources

I’ve Completed the RayWenderlich.com iOS Apprentice Tutorials Book!

I’ve been plugging along through the iOS Apprentice book from raywenderlich.com over the past few weeks. Let me say one thing: this thing is AMAZING.

RayWenderlich.com iOS Apprentice Book Synopsis

The iOS Apprentice is a series of epic-length tutorials for beginners where you’ll learn how to build 4 complete apps from scratch.

Each new app will be a little more advanced than the one before, and together they cover everything you need to know to make your own apps. By the end of the series you’ll be experienced enough to turn your ideas into real apps that you can sell on the App Store.

These tutorials have easy to follow step-by-step instructions, and consist of more than 900 pages and 500 illustrations! You also get full source code, image files, and other resources you can re-use for your own projects.

I started out by just signing up for the site’s newsletter. When you sign up for the newsletter, you get emailed the entire first full-length tutorial in the iOS Apprentice book for FREE. At first, I ignored the tutorial as I was focused on just grabbing what I needed from Googling, but I quickly became frustrated with the gaps in my knowledge.

I stumbled upon the RayWenderlich.com site tutorials quite often in my googling and saw that the site had some new Swift and iOS books coming out. I didn’t realize that the tutorial that I got for free with the newsletter sign up was actually the first of four chapters in the iOS Apprentice, and I was interested in buying the iOS Apprentice so I dug up the tutorial in my Gmail and decided to commit to going through it.

As soon as I made it through the first few pages, I knew this was going to be an amazing resource. I zoomed through the free tutorial and was hooked–I decided to bite and I actually bought the complete Mega Swift Bundle from RayWenderlich.com…that’s how sure I was that this was how I wanted to learn.

So as of today, I’ve completed the iOS Apprentice book–all 1,018 pages! I’ve learned so, so much, a lot of which is how to do iOS development in Swift the right way–not by hacking together a bunch of stuff I find online. My current unfinished app definitely has some ‘no-no’s’ in it that the book’s author, Matthijs, pointed out along the way that I’m going to have to go through and fix now that I know.

My next adventure: the RayWenderlich.com Core Data by Tutorials Book! To make my unfinished app work better, I need to get better at Core Data, so this will definitely help!

P.S.: I’m also making my way through the Swift Apprentice book bit by bit as I go along. Another great resource.

Standard
Tutorial Resources

Learning How To Use Carthage

I kept seeing references on github to CocoaPods and Carthage but had no clue how to use them or what they were for. 

Today I stumbled upon a tutorial on one of my favourite iOS/Swift tutorial sites RawWenderlich.com that went through explaining the W5s behind Carthage! 

Tutorial Link: Getting Started with Carthage

I did the whole tutorial and now all is clear and I can start using Carthage in my projects where it may be useful. 😀 Sometimes all it takes is a structured learning environment to make something crystal clear in my head!

I also now see how Carthage can be better than CocoaPods so I think I’ll stick to using Carthage in the future.

Standard