Discovering Native Swift Patterns

Patterns are your go-to code, the things you know exactly how to do in other languages because you’ve done them many times before. But what happens when a new language is released with its own unique syntax and features? We have to discover the patterns that feel at home in this new language; when to stick with what we know and when to branch out and do something new and different. This talk will cover some common patterns you might see in Objective‑C (and other languages) and developing equivalent patterns using clear, concise code through the lens of native Swift.


Introduction (0:00)

Thank you very much. I’m Nick O’Neill, and this is Discovering Swift Patterns.

Design patterns are generally small pieces of code that solve a very particular problem. Apps are made up of lots of these patterns all sort of put together.

A simple pattern can be where a tap takes you to the next screen. Something larger is something that you would use to manage access to core data. The idea may be that being a good programmer is knowing what patterns to use for which problems. But these patterns aren’t necessarily static, and particularly when a new language comes along, like Swift, we need to think about how to reexamine these patterns that we’re using in the context of another language and the language’s tools that are available to us.

That Thing in Swift (0:55)

I write a blog called That Thing in Swift, and I started it as an Objective‑C developer. When Swift came out, and I wanted to think about ways that we could take patterns in Objective‑C and translate them to Swift.

How can I express what I’m doing more clearly?

We kept on finding new ways to express what we wanted to say in more expressive ways with Swift. How can I express what I’m doing more clearly? So not just you when you come back to this code later on can understand what’s going on, but maybe you’re working with somebody else, and when you’re developing your code, you want them to be able to come in and pick right up where you left off and make changes.

Static Table Cell (2:30)

This is a basic static table view.

The Objective‑C way (2:41)

if (indexPath.section == 0) {
  if(indexPath.row == 0) {
    cell.textLabel.text = @"Twitter"
  } else if (indexPath.row == 1) {
    cell.textLabel.text = @"Blog"
  } else {
    cell.textLabel.text = @"Contact Us"
  }
} else {
  if(indexPath.row == 0) {
    cell.textLabel.text = @"nickoneill"
  } else if (indexPath.row == 1) {
    cell.textLabel.text = @"objctoswift"
  } else {
    cell.textLabel.text = @"@whyareyousodumb"
  }
}

You’d key off of all these sections and row indexes, and there’s lots of nesting going on and it’s confusing, and if you’re doing things after you select these cells, then you have a duplicate of all this stuff right below this. So, it’s a giant mess, and really not something we wanna do.

A better? Swift way (3:07)

let shortPath = (indexPath.section, indexPath.row)
switch shortPath {
  case (0,0):
    cell.textLabel.text = "Twitter"
  case (0,1):
    cell.textLabel.text = "Blog"
  case (0,2):
    cell.textLabel.text = "Contact Us"
  case (1,0):
    cell.textLabel.text = "@nickoneill"
  case (1,1):
    cell.textLabel.text = "@objctoswift"
  case (1,2):
    cell.textLabel.text = "@whyareyousodumb"
  default:
    cell.textLabel.text = " ̄\\_(θ)_/ ̄"
}

And a better Swift way might be to do it like this. We make a short little tuple out of the section and the row, and then we switch on that. Is this better?

We have all the sections right on the left there. Everything is lined up. You can sort of see the distinction between the sections and the rows, and it’s a little more clear. If you do see a switch statement outside of an enum maybe you should at least perhaps think about how it would work if you had an enum involved.

The best? Swift way (4:05)

enum TwitterHandles: Int {
  case Nickoneill
  case Objctoswift
  case Whyareyousodumb

  func labelText() -> String {
    switch self {
      ...
    }
  }
}

let rowData = TwitterHandles(rawValue: indexPath.row)
cell.textLabel.text = rowData.labelText()

This is a better way to do it. So here we have an enum, a raw value with an integer, and it represents one section of our table view cell, thus preserving the order there, and every time we create a table cell, we’re creating this enum object with the row that we’re handing.

And then we ask the enum object for the proper cell values. We’re relinquishing not just the order of these cells to the enum, but also the content for all of these cells is organized in the enum, and we gain the clarity of having this all in one location, but also the bonus of being able to add a new case right in the middle there without having to adjust all of our sections and indexes like we would have to do in the Objective‑C way or the naive Swift way.

Our Idea of the Best Swift Pattern Will Change Over Time (5:24)

I was surprised that my idea of what is the best Swift changed over time, and these great patterns that we run into, they feel like little hidden secrets in the language, and you start solving a problem one way, and you just keep solving it that way, because it’s very familiar and you sort of go along not knowing that there’s anything else, and then one day you’re pairing with somebody and they show you an entire different approach to a problem, and it feels amazing, right? Of course, this is a particularly dangerous trap to fall into, because it’s super tempting to just wanna use that new pattern that you learned that feels amazing absolutely everywhere, and the truth is, not every piece of clever code, not every improvement that we make, is a really great pattern. Just because we can simplify something to, say, a single line of code, doesn’t necessarily make it better, it definitely doesn’t make it clearer in all the cases.

Not Every Piece of Clever Code is a Great Pattern (5:53)

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  // do some task
  dispatch_async(dispatch_get_main_queue(), ^{
    // update some UI
  });
});

So let’s take a look at another example in Objective‑C. You go off to the background thread to do some sort of processing that takes some significant amount of time, and then when you’re done, you come back to the main thread to update your UI.

In Swift, we can really easily wrap this up in a few short pieces of syntax so that we can use it in multiple places.

func mainToBackground(background:() -> (), main: () -> ()) {
  let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
  dispatch_async(dispatch_get_global_queue(priority, 0)) {
    background()
    dispatch_async(dispatch_get_main_queue()) {
      main()
    }
  }
}

mainToBackground({
  // do some task
}, {
  // update the ui
})

We take two closures, one we run on the background thread, once that’s finished we take the other closure, which we run on the main thread. And we’ve called this main to background. Now, the problem with this is that we can go further with Swift, right? We can get too fancy.

{ /* do some task */ } ~> { /* update some UI */ }

Here’s a custom operator that executes the left hand side closure on the background thread and the right hand side closure on the main thread, right? Sure, it’s one line, but it’s not really clear what the intention is, and that little operator might get lost once you have any significant amount of code in either the left or the right hand side closure. And if you started to work on a code base and you came in and had to learn all these little non-standard patterns, that’s not super clear, and I think you would not enjoy working on that project very much. So is it clear? Not really, but sure, it’s concise.

Great Patterns Provide Convenience While Maintaining Clarity (7:50)

Great patterns provide convenience while maintaining clarity. We should be aiming for people who are even first time programmers, people who are coming to Swift for the first time, understanding this. They have a hard enough time adapting to operators like modulo, which are present in lots of languages. So that’s my general take on custom operators, just don’t.

Setup Pattern for Adding Views to a View Controller (8:23)

class ViewController: UIViewController {
  let imageView = UIImageView()
  let goButton = UIButton()

  override func viewDidLoad() {
    imageView.image = UIImage(named: "profile")
    view.addSubview(imageView)

    goButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
    goButton.setTitle("GO!", forState: .Normal)
    view.addSubview(goButton)
  }
}

Something like this is a traditional setup pattern for adding views to a view controller. It’s not much of a pattern as much as you just throwing everything into viewDidLoad, and I am as guilty of this as anybody else. Even here where there’s just two subviews, this is already getting sort of out of hand. You really can’t tell what’s happening when, and with a realistic number of views and even a moderately complex view controller, this gets out of hand very, very quickly. What can we do in this case?

Initialization closures are one of my favorite patterns in Swift.

class ViewController: UIViewController {
  let imageView: UIImageView = {
    let imageView = UIImageView()
    imageView.image = UIImage(named: "profile")
    return imageView
  }()

  let goButton: UIButton = {
    let button = UIButton()
    button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
    button.setTitle("GO!", forState: .Normal)
    return button
  }()

  override func viewDidLoad() {
    view.addSubview(imageView)
    view.addSubview(goButton)
  }
}

What we’re doing here is creating a closure that configures the type we want and returns it. That’s all it does. It’s called immediately when the class is loaded. And it’s super easy to break this single, monolithic viewDidLoad into all these separate initialization closures, and you never have to guess what’s going on in each area. If it’s in an initialization closure, it’s configuring a view, it’s returning a view.

Why I like this pattern so much is that I finally feel like I’ve escaped the confines of throwing everything into viewDidLoad. I’m finally using all these separate view lifecycle methods as they were originally intended, or at least as their named, right? So is it clear? For sure. Is it precise, or is it concise? It’s got a little bit of boilerplate associated with it, but I’d say, considering the mess of viewDidLoad, it’s probably awash at the end of the day. So these guys are great for organizing your view configuration. I highly recommend it.

We can use a very similar pattern to help with storyboard view configuration, as well.

@IBOutlet weak var arrivalLabel: UILabel! {
  didSet {
    arrivalLabel.text = "Arriving in 10 minutes".uppercaseString
    arrivalLabel.font = UIFont(name: "Lato", size: 11)
    arrivalLabel.textColor = UIColor.blueColor()
    arrivalLabel.textAlignment = .Center
    arrivalLabel.numberOfLines = 1
  }
}

Storyboards are great for auto layout, but they’re terrible for dependency injection, and they’re awful for view configuration. So I tend to do a lot of basic layout in storyboards, and then I keep the view configuration in these didSet blocks in the view controller.

Once the UILabel gets set via the IBOutlet, runs through all this configuration.

Optionals are super great for modeling data in your app, whether or not you’re expected to have data as it’s flowing through your app, but they can add a lot of bulk to relatively simple operations, like this one, where you’re saying, “Take these selected index paths, “and deselect all of them.”

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)

  if let paths = tableView.indexPathsForSelectedRows {
    for path in paths {
      tableView.deselectRowAtIndexPath(path, animated: true)
    }
  }
}

You’re doing this, let’s say, in viewDidAppear as you’re doing here, where, let’s say, you’re coming back from another view controller, you wanna deselect all the index paths of those table view cells. And, it’s straightforward to understand, but it just feels like there’s more code here than is necessary for the basic thing that we’re doing. And it’s mostly because we have to handle this optional array. There’s no guarantee that the array is gonna return anything at all, so rather than it being empty, which would make sense to me, it’s also an optional. So there are a lot of built in tools that can help us out with this. ForEach takes optional arrays, so we can replace our entire optional check here just with forEach, and it does the natural thing.

tableView.indexPathsForSelectedRows?.forEach({ (path) in tableView.deselectRowAtIndexPath(path, animated: true )})

If there’s nothing, it just takes no operations, and if there are index paths in there, it’ll give us each index path, and then we can deselect that, and we shave off some unnecessary annotation. We can make this even more compact using trailing closure, and admitting the argument name in favor of argument position.

tableView.indexPathsForSelectedRows?.forEach{
  tableView.deselectRowAtIndexPath($0, animated: true )
}

And in this case, I actually think it’s an acceptable trade off. It’s clear that you’re getting index paths back. They’re only used in one obvious case. If this closure was any more complex,

Simple Patterns can Replace Large Dependencies (13:00)

Plenty of things that feel like they should be complex aren’t necessarily complex, and you don’t always need some large, general purpose framework when a simple pattern will do. Here’s an example of a JSON parsing library that I love to use, Unbox.

let json = try? NSJSONSerialization.JSONObjectWithData(data, options: [])

if let object = json as? Dictionary<String, AnyObject>,
  places: [Place] = Unbox(object) {
    return places
  }

It has a lot of great features for turning complex JSON into structs. I do it all the time for network stuff. But, a lot of the time, I just don’t need to. It’s just not necessarily required. If you’re in your network manager here, this should be very clear for people who have done JSON serialization before, you’re taking your data, you’re turning it into some sort of an object, we’re verifying that it’s a dictionary, and then we pass it to Unbox and we hope it gives us a struct that’s appropriately typed.

struct Place: Unboxable {
  let id: String
  let address: Int?
  let text: String

  init(unboxer: Unboxer) {
    self.id = unboxer.unbox("id")
    self.address = unboxer.unbox("address")
    self.placeName = unboxer.unbox("place_name")
  }
}

We have to set up our struct like this with a special initializer that gets the correct types. But you’re getting such basic data here, there’s not a whole lot of extra code that you have to write on top of doing this yourself. So, if you implemented, a failable initializer pattern on this struct, then it’s a pretty easy way for you to get started without using any fancy libraries. You have guard when unwrapping the required pieces, like the ID, and then the rest of them you can either provide a default like we did with placename here, or assign them just as optionals like they’re cast.

struct Place {
  // ...

  init?(json: Dictionary<String, AnyObject>) {
    guard let id = json["_id"] as? String else {
      return nil
    }
    self.id = id

    self.address = json["address"] as? Int

    self.placeName = (json["name"] as? String) ?? "No place name"
  }
}

And if this fails, you know exactly where to debug to figure out what’s not casting properly. You don’t have to set a breakpoint on some magic selector like you’d have to do to debug some framework that’s doing it for you.

Architecture is something you learn over time, and it takes a little bit more time to get the big architecture together, rather than just me showing you a short little pattern on a slide. There’s lots of opportunities to develop these sort of large, smart architectural decisions that become patterns that you can use in lots of projects, stuff like networking, core data, how you communicate over all your app, like notification center and KVO delegates.

Patterns are great. We love patterns, and there’s lots of opportunity to do things in a better way, and you wanna develop your own patterns, so let’s figure out how to start.

Tips for Finding New Patterns (17:17)

One: develop an intuition for code smell. Any code that you dread changing fits here. Anything that feels like Objective‑C, places where you see stringly typed things, they’re great opportunities for you to replace that with a pattern that feels a lot more natural, a lot more Swifty for you. It’s helpful to experiment without the extra demand of a real project.

Two: Open up a playground or open up a new project and just start hacking on something that’s small and contained, and then from there, you can scale it up to a real project, and if it ends up not fitting whatever your real project need was, then that’s part of experimentation, but starting small is definitely easier to start developing these new patterns. You don’t have to jump right in and throw it in your gigantic app first.

Three: reread the language guide. The language guide is surprisingly dense. Well, maybe not surprisingly dense, but it is dense, and it can feel very basic when you’ve already learned Swift, but it’s actually a trove of hidden gems, and stuff you didn’t realize existed when you first read through it because you were astounded by all this awesomeness that is Swift, if you reread relevant sections with your problem in mind, or even just glance through the whole thing now that you have a better understanding of Swift, it really brings to mind a lot of interesting things that you sort of forgot about when you went through it or didn’t notice, that sort of thing. That’s actually how I came upon didSet again, after a while, I was just browsing the guide for something else, maybe I came upon it for something else, and I was like, “This is really useful. “Why don’t I use this?”

Four: remember to keep things clear. It is easy to fall into the clever code trap. You should think like a first time Swift user, and try and see it like they would, or at the very least, try and show your code to, say, a coworker or someone who might not know Swift and see what they feel about what your code is doing and that sort of thing to get their sense of it.


Nick O'Neill

Nick O'Neill

Nick O'Neill is an independent iOS developer in San Francisco. He writes about creating clear, concise Swift patterns at That Thing in Swift.