Custom init of UIViewController from storyboard
A simplification of my prior answer which is quick and avoids alternative hacky fixes:
Here is a detail view controller you may want to instantiate from storyboard with an objectID set:
import UIKitclass DetailViewController: UIViewController { var objectID : Int! internal static func instantiate(with objectID: Int) -> DetailViewController { let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DetailViewController") as DetailViewController vc.objectID = objectID return vc } override func viewDidLoad() { super.viewDidLoad() if((objectID) != nil){ print("Here is my objectID: \(objectID)") } }}
Here is how you would use it to push onto a navigation controller with objectID set to 1:
self.navigationController.pushViewController(DetailViewController.instantiate(1), animated: true)
Added a blog post:https://theswiftcook.wordpress.com/2017/02/17/how-to-initialize-a-storyboard-viewcontroller-with-data-without-segues-swift-3-0git/
Link to example on GitHub:https://github.com/hammadzz/Instantiate-ViewController-From-Storyboard-With-Data
Below are two helpers, one is a Storyboard enum, add each and every storyboard in your project as a case under this enum. The name must match the {storyboard_name}.storyboard file. Each view controller in your storyboard should have its storyboard identifier set to the name of the class. This is pretty standard practice.
import UIKitpublic enum Storyboard: String { case Main case AnotherStoryboard //case {storyboard_name} public func instantiate<VC: UIViewController>(_ viewController: VC.Type) -> VC { guard let vc = UIStoryboard(name: self.rawValue, bundle: nil) .instantiateViewController(withIdentifier: VC.storyboardIdentifier) as? VC else { fatalError("Couldn't instantiate \(VC.storyboardIdentifier) from \(self.rawValue)") } return vc } public func instantiateInitialVC() -> UIViewController { guard let vc = UIStoryboard(name: self.rawValue, bundle: nil).instantiateInitialViewController() else { fatalError("Couldn't instantiate initial viewcontroller from \(self.rawValue)") } return vc }}extension UIViewController { public static var defaultNib: String { return self.description().components(separatedBy: ".").dropFirst().joined(separator: ".") } public static var storyboardIdentifier: String { return self.description().components(separatedBy: ".").dropFirst().joined(separator: ".") }}
Here is how you can instantiate from storyboard with a value set in your view controller. Here is the magic:
import UIKitclass DetailViewController: UIViewController { var objectID : Int! var objectDetails: ObjectDetails = ObjectDetails() internal static func instantiate(with objectID: Int) -> DetailViewController { let vc = Storyboard.Main.instantiate(DetailViewController.self) vc.objectID = objectID return vc } override func viewDidLoad() { super.viewDidLoad() if((objectID) != nil){ // In this method I use to make a web request to pull details from an API loadObjectDetails() } }}
(Architecture influenced/copies Kickstarter's open source iOS project)
An (ugly) way to solve this issue:
You can set your let i
from an external buffer in your code (AppDelegate variable in this example)
required init?(coder aDecoder: NSCoder) { self.i = UIApplication.shared().delegate.bufferForI super.init(coder: aDecoder)}
And when you initiate your UIViewController through Storyboard:
UIApplication.shared().delegate.bufferForI = myIValueself.navigationController!.pushViewControllerFading(self.storyboard!.instantiateViewController(withIdentifier: "myViewControllerID") as UIViewController)
EDIT:You don't have to pass the value through the AppDelegate. Better answer here.