Use enums as identifiers for storyboard segues

Have you ever seen a crash like this?

*** Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'Receiver ()
has no segue with identifier 'Ніч яка місячна зоряна, ясная.''

Usually you face this problem, when you use performSegueWithIdentifier(_:sender:) method of UIViewController  class. Storyboards' identifiers are plain strings, that’s why it’s easy to mistype them.

Personally, I use an enum that holds all segues' identifiers:

import UIKit

public enum SegueId: String {
    case Unknown = "Cuy'val Dar"

    // Add more case clauses here for each storyboard segue
    case EditReceiptDetails = "Edit receipt details"

    public init(segue: UIStoryboardSegue) {
        self = SegueId(rawValue: segue.identifier ?? SegueId.Unknown.rawValue) ?? SegueId.Unknown
        assert(self != .Unknown)
    }
}

This allows me to be sure, that I didn’t mistype a segue’s identifier:

private func performSegueWithIdentifier(identifier: SegueId, sender: AnyObject?) {
    performSegueWithIdentifier(identifier.rawValue, sender: sender)
}

private func createAddExpensesAlertController() -> UIAlertController {
    let alertController = UIAlertController(title: nil,
                                          message: NSLocalizedString("How you would like to add expenses?"),
                                   preferredStyle: .ActionSheet)

    let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel"), style: .Cancel) {
        action in
        ()
    }

    let manuallyAction = UIAlertAction(title: NSLocalizedString("Manually"), style: .Default) {
        action in
        self.performSegueWithIdentifier(.AddExpensesManually, sender: alertController)
    }

    let scanReceiptAction = UIAlertAction(title: NSLocalizedString("Scan receipt"), style: .Default) {
        action in
        ()
    }

    alertController.addAction(cancelAction)
    alertController.addAction(manuallyAction)
    alertController.addAction(scanReceiptAction)

    return alertController
}

Please, note the performSegueWithIdentifier method overload in the code above. You could create an extension for the UIViewController class to make it available in all view controllers:

import UIKit

public extension UIViewController {
    public func performSegueWithIdentifier(identifier: SegueId, sender: AnyObject?) {
        performSegueWithIdentifier(identifier.rawValue, sender: sender)
    }
}

Also, you could use strongly-typed enums instead of plain strings in prepareForSegue(_:sender:) method of the UIViewController class:

public override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let segueId = SegueId(segue: segue)

    switch segueId {
    case .AddExpensesManually:
        // Prepare for this specific segue
        ()
    case .EditReceiptDetails:
        // Prepare for this specific segue
        ()
    default:
        ()
    }
}

This approach is helpful for me and I hope it will be helpful for someone else as well.