top of page

Delegation in Swift: Passing Data Between Two View Controllers

Updated: Jul 2, 2020

Delegation is a very important design pattern in iOS development. In this example we will see how a base class can hand off functionality to a secondary class using a delegate. The secondary class will be able to pass data back to the base class while the two classes are decoupled.


Let’s start by creating a SingleView iOS app. Let’s rename our ViewController.swift to SourceViewController.swift. Make sure you change the name of the class in the Identity Inspector as well.


Add another View Controller to your main storyboard. Let’s now create the Swift file that contains the code for this View Controller. When we drag a view controller object into our storyboard it doesn’t automatically create the new class for you.


We will create the class for the second View Controller by adding a Cocoa Touch class file to our project. We choose the Cocoa Touch file and not a new Swift file because the Cocoa class files imports the UIKit which provides all the components associated with your typical UI, storyboard or view controllers. In contrast, a standard Swift file only imports the Foundation API. Basically, the difference between these two options is in the boilerplate code each file type inherits.


Let’s name this file DestinationViewController. Make sure you connect this second scene to the DestinationViewController class in the Identity Inspector.

You now have two View Controllers: SourceViewController and DestinationViewController as well as their corresponding swift classes.


We now want to embed the SourceViewController within a navigation controller in the storyboard in order to handle navigation between views and have a navigation bar at the top of the screen (Choose Editor > Embed In > Navigation Controller). The navigation bar automatically shows a back button for you to go back to the previous view controller (from Destination to Source).


Let’s now add a Button and a Label to our SourceViewController.

We’ll change the title for the Button to “Delegate To Destination”. The Label text should be empty. Also allow 5 lines of text for the label in the Attributes Inspector. This label will receive the text that we will add in the Destination View Controller Scene. Let’s change the background for the label to light grey so you can see it in the storyboard.


In the Destination View Controller Scene also add a Button and a Text field. Change the Title for the Button to “Send Quote Back”. Leave the Text for the Text field empty. Here is where we will enter our text/quote and then send it back to the SourceViewController.


Your storyboard should now look like this:

When we click the Button in the SourceViewController, we want to send the user to the second View Controller.

Open the Assistant Editor, by hitting the little button with the two circles, to show the ViewController.swift file alongside the Storyboard.

Control-drag from the Button to the source code file and when it drops, select Action in the Connection dropdown and give it the name goToDestinationView and hit Connect.

You should now see the following function added to your SourceViewController class. This function will be ran any time a user hits this Button.

 @IBAction func goToDestinationView(_ sender: Any) {
 }

Select the Destination View Controller and in the Identity Inspector add a unique Storyboard ID - let’s call it DestinationVCID.

Now let’s add the necessary code for the goToDestinationView function to go to the next View Controller (ensuring the class, storyboard name and story board ID match those that you are using).


 @IBAction func goToDestinationView(_ sender: Any) {

 // Instantiate the Destination view controller using its Storyboard name in Xcode
 //Here we create a reference to our current storyboard
 let storyboard = UIStoryboard(name: "Main", bundle: nil)

 // Instantiate the desired view controller from the storyboard using the view controllers identifier
 // Cast is as the custom view controller type you created in order to access it's properties and methods
 
 let vc = storyboard.instantiateViewController(withIdentifier: "DestinationVCID") as! DestinationViewController
 
 //Pushing the DestinationViewController and updating the display
 self.navigationController?.pushViewController(vc, animated: true)
 }

You can run the application now. You should be able to switch between the two scenes and enter text in the Text field in the Destination Scene.

There are many ways to send the data from the Destination View back to the Source View. In this example we will use Delegation.

Delegation, also known as the Delegate Pattern, is used frequently in iOS development.

How does it work? Imagine you are part of the “Source” team which is supposed to write inspirational quotes for a local magazine.

However, you delegate this task to the “Destination” team. Once the “Destination” team is done, they send the quote back to you so you can send it to the local publisher. You are in charge of sending the quote to the publisher but you delegate the task to another team. Basically, you’re handing off that responsibility to the “Destination” team. Once the “Destination” team finishes writing the quote, they send it back to you (the “Source” team).


In our example, the Source class delegates the activity to the Destination class. To do that, we first need to define a protocol that will encapsulate the responsibility that we are delegating.

Let’s create a new Swift file and add a protocol named QuoteDelegate.

This QuoteDelegate protocol defines one function onQuoteReady(type: String). This delegate function will get called whenever a quote has been written and it's ready by the “Destination” team (in our case it is the text entered in the Text field part of the Destination View Controller Scene).

protocol QuoteDelegate: AnyObject
{
 func onQuoteReady(quote: String)
}

We want the “Source” team to adopt and conform to our QuoteDelegate protocol. We need to add the protocol to our Source class by placing protocol’s name after the type’s name, separated by a colon, as part of their definition.

class SourceViewController: UIViewController, QuoteDelegate {
…
}

After adding the protocol name, we get an error: Type 'SourceViewController' does not conform to protocol 'QuoteDelegate’. This is because we didn’t implement the function onQuoteReady(). If you say you want to conform to a protocol, you also have to implement it. You add this function to SourceViewController:

 func onQuoteReady(quote: String) {
 <#code#>
 }

Since Delegates send messages (in our example it will be the quote from the “Destination”), we want the current instance of SourceViewController to be the one receiving the delegated quote writing activity - so the quote / text from the DestinationViewController comes back to the Source class (vc.delegate = self).

vc.delegate = self  //if we forget this line, the quote message goes nowhere…

 @IBAction func goToDestinationView(_ sender: Any) {
 let storyboard = UIStoryboard(name: "Main", bundle: nil)
 
 let vc = storyboard.instantiateViewController(withIdentifier: "DestinationVCID") as! DestinationViewController
 
 vc.delegate = self
 
 self.navigationController?.pushViewController(vc, animated: true)
 }

After we add this line of code we get an error message saying that “Value of type 'DestinationViewController' has no member 'delegate’”.

This is because we didn’t create the “delegate” property for the DestinationViewController class.

weak var delegate:QuoteDelegate?

Then we need to be able to call the onQuoteReady(type: String) function on delegate when the user clicks on the “Send Quote Back” Button. This is how we pass the quote back to the SourceViewController.

 @IBAction func onSendQuoteBack(_ sender: Any) {
 let myQuote: String = quoteEntered.text ?? "" //assign a default value in case the user doesn’t enter a quote in the text box
 
 delegate?.onQuoteReady(quote: myQuote)
 }

If you run the program and click on the “Delegate To Destination” Button, the DestinationViewController is invoked. You can now enter your favourite quote in the Text field and click on the Back button on the Navigation Bar to go back to the Main Screen (SourceViewController Scene).


You’ll see the quote entered in the DestinationViewController displayed on your label in the SourceViewController.


You can find the full code on Github. Hope you found this useful.


留言


I Sometimes Send Newsletters

Thanks for submitting!

© 2020 by Victor Balas @ devrazor.com

bottom of page