Skip to content

Instantly share code, notes, and snippets.

@msewell
Last active October 3, 2022 16:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save msewell/5e185518a553b7ba9743451b5b817b31 to your computer and use it in GitHub Desktop.
Save msewell/5e185518a553b7ba9743451b5b817b31 to your computer and use it in GitHub Desktop.
SegueHandlerType for Swift 3
/* The SegueHandlerType pattern, as seen on [1, 2], adapted for the changed Swift 3 syntax.
[1] https://developer.apple.com/library/content/samplecode/Lister/Listings/Lister_SegueHandlerType_swift.html
[2] https://www.natashatherobot.com/protocol-oriented-segue-identifiers-swift/
*/
protocol SegueHandlerType {
// `typealias` has been changed to `associatedtype` for Protocols in Swift 3.
associatedtype SegueIdentifier: RawRepresentable
}
extension SegueHandlerType where Self: UIViewController, SegueIdentifier.RawValue == String {
// This used to be `performSegueWithIdentifier(...)`.
func performSegue(withIdentifier identifier: SegueIdentifier, sender: Any?) {
performSegue(withIdentifier: identifier.rawValue, sender: sender)
}
func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier {
guard let identifier = segue.identifier, let segueIdentifier = SegueIdentifier(rawValue: identifier) else {
fatalError("Couldn't handle segue identifier \(String(describing: segue.identifier)) for view controller of type \(type(of: self)).")
}
return segueIdentifier
}
}
import UIKit
class ViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segueIdentifier(for: segue) {
case .showFoo:
// prepare for segue to Foo
break
case .showBar:
// prepare for segue to Bar
break
}
}
}
/* We're using a protocol extension here to separate UIViewController concerns.
See [1, 2] for more info on this.
[1] https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521
[2] https://www.natashatherobot.com/using-swift-extensions/
*/
extension ViewController: SegueHandlerType {
enum SegueIdentifier: String {
case showFoo
case showBar
}
}
@msewell
Copy link
Author

msewell commented Jul 21, 2017

@d108

When using an unwind segue, the segue identifier is nil.

Are you sure about that? I believe you can give your unwind segue an identifier in Interface Builder.

@simongardener
Copy link

I could be doing something wrong here (xcode 9.1 swift 4) but if i write the performSegue method as you do

    func performSegue(withIdentifier identifier: SegueIdentifier, sender: Any?) {
        performSegue(withIdentifier: identifier.rawValue, sender: sender)
    }

then when t type this
performSegue(withIdentifier: .measurements , sender: self)

I got no autocomplete after typing the period. I would have to explicitly add SegueIdentifier. to get the autocomplete to kickin

if, in the protocol extension, I change the performSegue to a different form, say by replacing the withIdentifier to _ as here
func performSegue(_ identifier: SegueIdentifier, sender: Any?) { performSegue(withIdentifier: identifier.rawValue, sender: sender) }
then I don't need to type SegueIdentifier but just start with .m and the autocomplete kicks in

the lack of Xcode autocompleting is a downside bigger than the benefit of having a method with the same parameter names Imho.

Of course, this is possibly just another Xcode bug :)

@aureliano2nd
Copy link

aureliano2nd commented Dec 12, 2018

Hi, thanks for the gist !

the switch statement would be swiftier without the break statements

class ViewController: UIViewController {

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        switch segueIdentifier(for: segue) {
        case .showFoo:
            // prepare for segue to Foo
        case .showBar:
            // prepare for segue to Bar
        }
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment