Passing Information Between View Controllers
Passing Information Between View Controllers
I don't know why, but for whatever reason one of the things that used to really drive me crazy was passing information between view controllers. I think it is just part of the learning curve, and Apple's strong encouragement toward some type of MVC inspired design pattern.
To help others who are trying to get a handle on this, I wrote up a very simple app that passes data between two view controllers. One has a text label that displays text, and the other one allows you to change the text displaying on the first one.
After setting up the view, and associating ViewController.swift files with each one, and setting up Storyboard IDs for each View, it's actually very simple to write code to pass the text between them. In my example, I set the segue up by right-click-dragging from the Enter Text button over to the other view controller and chose "Show" for the segue type.
Without any code, the segue will work, but the two Views will have no way of talking to each other. You can do this using functionality straight from UIKit, specifically the "prepare(for segue:)" function, and the "presentingViewController" variable. We'll start with prepare(for segue:).
|The Prepare for Segue function in the base View Controller|
As you can see in the code snippet above, we are able to pass information in three lines of code. The first line is instantiating the View Controller we are about to go to. We force cast the TextEntryViewController class, to give us access to the properties we need to send data to. The next line simply accesses the text property, and assigns the value we want. In this case, the view controller we are sending from has some text it wants to send (thus the self keyword).
|viewWillAppear Method in TextEntryViewController|
To do something with the text that was sent, we can set our textField's placeholder text to it. We accomplish this in the line of code that reads:
textField.placeholder = text
After the user types something in the textField, and taps the "Set Label" button, sending the new text back is also very easy.
|Sending data back to the original view|
Storyboard views work like a stack of cards. When you "show" a new card, it gets put on the top of the stack. The last card you were looking at is still there, it's just covered up. Because of this, we don't want to instantiate a new ViewController, we want to access the one that's already there. This is the part that used to give me the most trouble, I kept wanting to instantiate new ViewControllers, which just kept stacking an endless deck, and would make a program unstable and slow. Luckily, doing it the right way is very easy. We can get access to the presenting view controller by creating a variable—similar to how we did it in prepare(for segue:)—but instead of creating a new view controller, we simply use "presentingViewController" to get access to the old view controller. We still want to force type, to give us access to the properties and methods we want to use. You can see this accomplished in the code above. Finally, instead of presenting a new view controller, we just need to dismiss the current view, because once that gets dismissed we will get back to the old one.
You can get a better feel for how it all works by downloading the project from GitHub from the link at the bottom of this post, and playing around with it a little bit. The main take-away is to keep thinking about storyboard views as a stack of cards.
In my example app I also used two UITextFieldDelegate functions. The delegate design model is probably the most powerful thing in the Swift language. You can tell your class to conform to a delegate by setting your class up like this:
You can actually create a class that specifically handles the delegate functions, to keep your code clean. I only used two functions, and the code was very simple, so I just added the delegate to my TextEntryViewController class. Next you have to tell the textField's who their delegate is, otherwise your delegate functions won't do anything. You can scroll up to the viewWillAppear code snippet above to see how this is done.
The code snippet below shows the two delegate functions I implemented. A useful trick in XCode is to hold down the option key while hovering over a class, or delegate. You will see the mouse cursor turn into a question mark, and if you click, you can get more details about whatever you are hovering over. If you don't know how to implement a delegate, or class, this is the best way to find out.
The textFieldDidBeginEditing allows you to do things when a user taps into a textField. Here, I just wanted to clear the placeholder, and any text that had been entered into the field before by setting both properties to empty strings.
Another point of frustration to drive a new Swift developer crazy, is dismissing the keyboard after the user taps out of a textField, or taps the return key. It doesn't do it automatically. The solution is found in the textFieldShouldReturn delegate function. This gets called when the user taps return, or tries to leave the text field. The following line of code will get rid of the keyboard for you:
I don't know how long it took me to figure this out when I was just getting started, but I do remember that it drove me nuts for hours!
Please check the example project out on GitHub. I hope that the project and this article help you understand how to pass information between view controllers!