Xibs, storyboards, or programmatic view controllers… what to use? My answer? It depends. Very helpful, I know! I’ll elaborate. In order of what I’m most likely to use:
I’ve been meaning to experiment with xibs more, since they allow for dependency injection through the initializer, but haven’t quite needed it yet. I digress…
Anyhow! I wanted to share a Swift snippet with you to help with number 1 up there. It’s not unique, ground-breaking or new by any means, but it’s useful and it feels nice. Without any bells or whistles, here it is in all it’s glory.
import UIKit
/// A protocol conformed to by all view controllers that expect to be
/// instantiated from a storyboard.
public protocol StoryboardDesigned: class {
static var storyboard: Storyboard<Self> { get }
}
/// By default, a storyboard-designed view controller has named the storyboard
/// it belongs to the same as itself, sans `Controller`, and is the initial view
/// controller.
///
/// - example: PostViewController -> PostView.storyboard
public extension StoryboardDesigned where Self: UIViewController {
public static var storyboard: Storyboard<Self> {
let className = String(describing: self)
let storyboardName = className.replacingOccurrences(of: "Controller", with: "")
return Storyboard<Self>(storyboardName, identifier: nil, bundle: nil)
}
}
/// A simple wrapper-type that we use to identify storyboards.
public struct Storyboard<T> {
let name: String
let identifier: String?
let bundle: Bundle?
init(_ name: String, identifier: String? = String(describing: T.self), bundle: Bundle? = nil) {
self.name = name
self.identifier = identifier
self.bundle = bundle
}
var storyboard: UIStoryboard {
return UIStoryboard(name: name, bundle: bundle)
}
func instantiate() -> T {
guard let identifier = identifier else {
return storyboard.instantiateInitialViewController() as! T
}
return storyboard.instantiateViewController(withIdentifier: identifier) as! T
}
}
By using the above code, and assuming you stick to my convention of naming your single-view storyboards the same as your view controller, and mark it as the initial view controller of the storyboard, then you may use the above code like this:
final class PostViewController: UIViewController, StoryboardDesigned {
// … outlets and other code in here …
}
func showPostViewController(from viewController: UIViewController) {
let postViewController = PostViewController.storyboard.instantiate()
viewController.present(postViewController, animated: true, completion: nil)
}
That’s all! There’s nothing more for now. Thanks for reading, I hope you found it worthwhile.