-
-
Save msewell/5e185518a553b7ba9743451b5b817b31 to your computer and use it in GitHub Desktop.
/* 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 | |
} | |
} |
Even better to turn:
func segueIdentifier(forSegue segue: UIStoryboardSegue) -> SegueIdentifier {
...
}
into:
func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier {
...
}
😄
You're both quite right! I've updated the Gist.
@msewell, thanks for sharing your code.
When using an unwind segue, the segue identifier is nil
. The following modifications can take care of this while still catching missing SegueIdentifier
cases.
func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier? {
guard let identifier = segue.identifier else {
return nil
}
guard let segueIdentifier = SegueIdentifier(rawValue: identifier) else {
fatalError("Couldn't handle segue identifier \(identifier) for view controller of type \(type(of: self)).")
}
return segueIdentifier
}
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.
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 :)
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
}
}
}
I think it's better to turn:
into
and also
ShowFoo
->showFoo
,ShowBar
->showBar
It's more Swift3 like