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.