Swift 2: Test Driving the Error Handling
I’d admit it, when Chris Lattner explained the new Swift 2 error handling code on Tuesday at WWDC (session available here), I was a bit overwhelmed. It looked pretty alien, Java-like, and unnecessarily complex. I felt like I’d have to sit down for a while to try to understand it.
However, yesterday morning for my Alt Conf talk, I had to change one of my code samples to Swift 2 code, with error handling included. While I did have to reference the slides from the WWDC session, the implementation turned out to be very easy, clean and natural!
The example I used was a very simple form with a name and an age text fields:

The implementation is as follows:
Model
The model is a simple Person value:
struct Person {
let name: String
var age: Int
}
View Model
To mitigate between the messiness of the data entry in the form and the clean model, I created a View Model:
struct PersonViewModel {
var name: String?
var age: String?
}
Since the view model is aware of the latest name and age data entry, it’s the perfect place to actually create the Person model. The problem of course, is that there are a few things that could go wrong before the model can be created. First, the user might not fill out all the required fields (name and age), or the age might be formatted wrong. This is where the error handling comes in! I’ve defined my Error Types as follows:
struct PersonViewModel {
var name: String?
var age: String?
enum InputError: ErrorType {
case InputMissing
case AgeIncorrect
}
}
Finally, I can create the person using the new Swift 2 error handling syntax:
struct PersonViewModel {
var name: String?
var age: String?
enum InputError: ErrorType {
case InputMissing
case AgeIncorrect
}
func createPerson() throws -> Person {
guard let age = age, let name = name
where name.characters.count > 0 && age.characters.count > 0
else {
throw InputError.InputMissing
}
guard let ageFormatted = Int(age) else {
throw InputError.AgeIncorrect
}
return Person(name: name, age: ageFormatted)
}
}
Things I love about this:
- I don’t have to return an optional!
- the guard is super clean looking and easy to understand
- I can put multiple conditions in my guard statement – I unwrap the age and name at the same time, since they produce the same error in this case
ViewController
Finally, I can easily catch the error in my ViewController when the user taps the Submit button:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var ageTextField: UITextField!
var personViewModel = PersonViewModel()
override func viewDidLoad() {
super.viewDidLoad()
}
func textFieldDidEndEditing(textField: UITextField) {
personViewModel.name = nameTextField.text
personViewModel.age = ageTextField.text
}
@IBAction func onSubmitButtonTap(sender: AnyObject) {
view.endEditing(true)
do {
let person = try personViewModel.createPerson()
print("Success! Person created. \(person)")
} catch PersonViewModel.InputError.InputMissing {
print("Input missing!")
} catch PersonViewModel.InputError.AgeIncorrect {
print("Age Incorrect!")
} catch {
print("Something went wrong, please try again!")
}
}
}
I love how simple and easy-to-read the error catching is!
Pingback: Michael Tsai - Blog - WWDC 2015 Links()