I am new to Swift and am building an app to learn. Right now I am making the registration section of the app.
I thought the UX would be better if there were multiple VC’s asking a single question, i.e. one for your name, one for your birthdate, etc as opposed to jamming all that into a single view controller. The final view controller collects all of that information and sends a dictionary as FUser object to be saved on Firebase.
I figured I could instantiate the final view controller on each of the previous five view controllers and pass that data directly to the end. I kept getting errors and figured out that the variables were nil. It works just fine if I pass the data directly to the next view controller but it doesn’t seem to let me send it several view controllers down. Obviously there’s a nuance to how the memory is being managed here that I’m not tracking.
Is there a way to do what I am trying to do or do I have to pass the data through each view controller along the way?
import UIKit
class FirstViewController: UIViewController {
//MARK: - IBOutlets
@IBOutlet weak var firstNameTextField: UITextField!
//MARK: - ViewLifeCycle
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - IBActions
@IBAction func continueToMiddleViewController(_ sender: Any) {
let vcFinal = storyboard?.instantiateViewController(withIdentifier:
"finalVC") as! finalViewController
vcFinal.firstName = firstNameTextField.text
let vc = storyboard?.instantiateViewController(withIdentifier:
"middleVC") as! middleViewController
vc.modalPresentationStyle = .fullScreen
present(vc, animated: false)
}
...
}
import UIKit
class FinalViewController: UIViewController {
var firstName: String?
...
//MARK: - ViewLifeCycle
override func viewDidLoad() {
super.viewDidLoad()
}
...
}
3
Answers
TL;DR: The fastest one that would solve your problem is creating a singleton
There are many strategies for this. For a starter, it might be a good idea to read some begginer articles, like this one. I can update this answer if you don’t find it useful, but it’d look just like the article
Viewcontroller
‘s variable can’t be initiated until any of the init method is called.There are detailed answers on this thread.
Passing Data between ViewControllers
Another way to approach this problem could be to make use of closures. Note that personally I’ve moved away from using storyboards but I’ll try to explain still. Closures are also referred to as callbacks, blocks, or in some context like here – completions.
You can declare a closure like
let onSubmitInfo: (String?) -> Void
below, it stores a reference to a block of code that can be executed at a later stage just like a function and it takes an optional string as a parameter just like a function can.The closures are specified in the initialisers where a block of code is passed into the respective classes below and the closures are then called in the
IBAction
s that will trigger the block of code that is defined where the below classes are initialised:To manage showing the above views and collecting the values returned by their closures (i.e.
onSubmitInfo
) we create aFlowController
class that will also show the next view when the closure is called.In
FlowController
we define the closures or blocks of code to be executed when it is called inside theIBAction
in the respectiveFirst
andSecond
classes above.The optional string that is provided in the respective
First
andSecond
classes is used as the(firstName)
and(secondName)
closure properties below:The
FlowController
finally shows theFinal
view controller after it has collected thefirstName
form theFirst
view controller and thelastName
form theSecond
view controller in theshowFinalView
function above.I hope this is a shove in the right direction. I have moved away from storyboards because I find creating views in code is more verbose and clear on peer reviews and it was also easier for me to manage constraints and just to manage views in general.