I tried finding some relevant questions but couldn't get anything, hope someone can help.
I set up some UIViewController's on a storyboard. I then want to load one of the view controllers in code and push it onto the navigation stack. I figure out the right way to do this is to use
instantiateViewControllerWithIdentifier
This calls init(coder: NSCoder) and all is well, my program works, but I want to be able to have a custom initializer that sets up some variables for my view controller. Consider the following:
class A : UIViewController {
let i : Int
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// property self.i not initialized at super.init call
}
}
I obviously get an error since i needs to be specified at time of object creation. Any solutions to this? I am not interested in declaring i as var and configuring it later as that defeats the point and I no longer have a compiler guarantee that i is immutable.
Suppose I have a currently loaded ViewController that has some variable i. This value is variable and can change. Now suppose from this ViewController I want to present another one, and initialize it with i.
class ViewController: UIViewController {
var i : Int
// ... other things
// in response to some button tap...
@IBAction func tappedButton(sender: AnyObject) {
let st = UIStoryboard(name: "Main", bundle: nil)
let vc = st.instantiateViewControllerWithIdentifier("AControllerID") as! A
// How do I initialize A with i ?
self.presentViewController(vc, animated: true, completion: nil)
}
}
I don't seem to be able to do this and keep i immutable by using let instead of var.
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 UIKit
class 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
Starting from iOS 13, you can use newly updated API, while instantiating UIViewController from Storyboard.
First, let's create custom initializer for UIViewController, that uses NSCoder:
final class ViewController: UIViewController {
var someProperty: Int
init(coder: NSCoder, someProperty: Int) {
self.someProperty = someProperty
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Later on, you can create ViewController, using updated API:
let viewController = UIStoryboard.yourStoryboard.instantiateViewController(identifier: String(describing: ViewController.self)) { creator in
let viewController = UIViewController(coder: creator, someProperty: someValue)
return viewController
}
As you can see, in the closure, we're passing our new initializer. This method of viewController creating is powerful, as we can(finally!) use initializers, that depends on required init(coder: NSCoder), when viewController are creating with UIStoryboard.
For more information, see here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With