Reputation: 1721
First I checked this post and it wasn't useful
I want to apply dependency injection on navigation from a controller to another,
let's say I have controller A :
import UIKit
class A: UIViewController {
}
and a controller B :
import UIKit
class B: UIViewController {
var name : String!
}
I'm navigating from A to B in this way :
let bViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BVC")
as! B
bViewController.name = "HelloWorld"
self.navigationController?.pushViewController(bViewController, animated: true)
I want to convert my code in order to be using dependency injection through initializers.
can any one advice if this can be done, and if can be done how ??
thnx in advance.
Upvotes: 3
Views: 4163
Reputation: 2293
class B: UIViewController {
var name: String
init?(coder: NSCoder, name: String) {
self.name = name
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("You shouldn't initialize this controller using init(coder:)")
}
}
Then when you want to navigation from A
to B
:
func pushToAContoller {
guard let vc = storyboard?.instantiateViewController(identifier: "AController", creator: { coder in
return A(coder: coder, name: "SomeName")
}) else {
fatalError("Failed to load A from storyboard.")
}
navigationController?.pushViewController(vc, animated: true)
}
Upvotes: 0
Reputation: 402
Starting with iOS13 Apple added functionality that allows us to do dependency injection at initialization.
You can do this by using a new method on UIStoryboard
called instantiateViewController(identifier:creator:)
. You have to define your own init
with the desired data and coder in the view controller to which you want to pass data and then call this init with the above mentioned method in the parent/presenting view controller.
See linked documentation and example below.
class ParentViewController: UIViewController {
@IBAction private func button() {
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ChildViewController") { coder in
return ChildViewController(coder: coder, userId: "123")
}
navigationController?.pushViewController(controller, animated: true)
}
}
class ChildViewController: UIViewController {
var userId: String
init?(coder: NSCoder, userId: String) {
self.userId = userId
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("Missing user id.")
}
override func viewDidLoad() {
super.viewDidLoad()
print("UserId: \(userId)")
}
}
Upvotes: 2
Reputation: 1558
class UserCredentials {
private let userDefaults: NSUserDefaults
private let authorizationTokenKey = "AuthorizationTokenKey"
init(userDefaults: NSUserDefaults) {
self.userDefaults = userDefaults
}
func getAuthorizationToken() -> String {
let value = userDefaults.stringForKey(authorizationTokenKey)
guard let retVal = value else { return "" }
return retVal
}
}
Upvotes: 0
Reputation: 3410
It is impossible since you use Storyboards. When you instantiate ViewController from Storyboard through instantiateViewController
method it uses required init?(coder aDecoder: NSCoder)
initialiser.
If you want to use your custom initialiser, you need to get rid of Storyboards and create UIViewController
only from code or from xib
file. So you will be able to make this:
import UIKit
class B: UIViewController {
var name: String!
init(name: String) {
self.name = name
super.init(nibName: nil, bundle: nil) # or NIB name here if you'll use xib file
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Also you need to provide init(coder...)
since every UI element can be instantiate from Storyboard. But you can leave it with default super
call, since you won't use it.
Another option is to use static
method in ViewController from the post in beginning of your question. But in fact it also assigns variables after ViewController's initialisation.
So no DI through initialisers for now. I would suggest to use separate struct
for all the data which need to be injected in VC. This struct will have all the necessary fields so you won't miss any of them. And you typical flow will be:
Data
structvar data: Data!
Upvotes: 6