How to Pass Data Between View Controllers Using Delegates (Swift)

There are several ways to pass data between View Controllers in an iOS app.

In this tutorial, we will explain how to pass values between View Controllers using Delegate in Swift.


As an example, we'll create a simple test app where the main screen has only a small input space for comments, and you can open a modal screen to enter multiple lines of comments.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 1

Preparing a Test iOS App to Pass Data

First, let's create a simple iOS app for testing data transfer.

In Xcode, create a new project under [iOS] > [App].

On the Main storyboard, add a small Text View and a button labeled “Comment” to the View Controller. The design and placement don't matter.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 2


Open the Assistant Editor, create an outlet for the Text View named commentTextView, and create a TouchUpInside action for the Comment button named commentTapped.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var commentTextView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func commentTapped(_ sender: Any) {
    }
}

Next, add another View Controller to be displayed modally.

First, generate a Custom Class file for the new View Controller.

From the Xcode menu, select [File] > [New] > [File from Template...].

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 3


Select [iOS] > [Cocoa Touch Class] and click [Next].

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 4


Enter a class name (here we'll use CommentViewController), set Subclass of to UIViewController, then click [Next] to generate the file.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 5


Go back to the Main storyboard, add a new View Controller, and set its Custom Class to CommentViewController.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 6


Add a large Text View and two buttons: “OK” and “Cancel.”

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 7


Open the Assistant Editor, create an outlet for the Text View named commentTextView, and actions for the buttons: okTapped and cancelTapped.

import UIKit

class CommentViewController: UIViewController {

    @IBOutlet weak var commentTextView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

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

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

Now, create a Segue between the two View Controllers.

Drag from the Comment button of the first View Controller to the CommentViewController.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 8

If you want to validate data before transitioning, you can create the Segue from the first ViewController itself and call performSegue(withIdentifier:sender:) inside commentTapped() when appropriate.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 8-2


Choose Present Modally.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 9


Select the generated Segue and set its identifier to showCommentSegue.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 10


Passing Values Between View Controllers Using Delegate

We will use a Delegate to pass the text back from the Comment View Controller to the first View Controller when either the OK or Cancel button is tapped.


From the Xcode menu, select [File] > [New] > [File from Template...], then choose [iOS] > [Swift File] and click [Next].

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 11


Create a Swift file named CommentDelegate.swift.

How to Pass Data Between View Controllers Using Delegate in iOS (Swift) 12


In CommentDelegate.swift, define a protocol called CommentDelegate like this:

import Foundation

protocol CommentDelegate: AnyObject {
    func commentEntered(text: String, cancelled: Bool)
}

The first View Controller will conform to this protocol, and when OK or Cancel is tapped in the Comment View Controller, it will call commentEntered() to return the value.


Update the first ViewController class as follows:

import UIKit

class ViewController: UIViewController, CommentDelegate {

    @IBOutlet weak var commentTextView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        commentTextView.layer.borderColor = UIColor.lightGray.cgColor
        commentTextView.layer.borderWidth = 0.5
        commentTextView.layer.cornerRadius = 5
        commentTextView.contentInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
    }

    @IBAction func commentTapped(_ sender: Any) {
        self.view.endEditing(true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showCommentSegue" {
            if let vc = segue.destination as? CommentViewController {
                vc.commentText = commentTextView.text
                vc.commentDelegate = self
            }
        }
    }

    func commentEntered(text: String, cancelled: Bool) {
        if !cancelled {
            commentTextView.text = text
        }
    }
}

Now, update the CommentViewController class like this:

import UIKit

class CommentViewController: UIViewController {

    var commentText: String?
    weak var commentDelegate: CommentDelegate?

    @IBOutlet weak var commentTextView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        commentTextView.layer.borderColor = UIColor.lightGray.cgColor
        commentTextView.layer.borderWidth = 0.5
        commentTextView.layer.cornerRadius = 5
        commentTextView.contentInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        commentTextView.text = commentText
    }

    @IBAction func okTapped(_ sender: Any) {
        self.view.endEditing(true)
        commentDelegate?.commentEntered(text: commentTextView.text, cancelled: false)
        self.dismiss(animated: true)
    }

    @IBAction func cancelTapped(_ sender: Any) {
        self.view.endEditing(true)
        commentDelegate?.commentEntered(text: commentTextView.text, cancelled: true)
        self.dismiss(animated: true)
    }
}

In the first ViewController, we conform to CommentDelegate by declaring it on line 3 and implementing commentEntered() on lines 29 - 33.

Inside commentEntered(), we check if cancelled is false, and if so, set commentTextView.text to the passed text.


Lines 10 - 13 set up the border of the Text View inside viewDidLoad(). For details, see How to Add a Border to a Text View.


Lines 16 - 18 are executed when the Comment button is tapped, which closes the keyboard with self.view.endEditing(true).


Lines 20 - 27 override the prepare(for:sender:) method.

prepare(for:sender:) is a method that is executed before the segue is performed.

When segue.identifier is showCommentSegue, we use if let to cast segue.destination to CommentViewController.

We then assign the value of commentTextView.text to the commentText property of CommentViewController, and set the commentDelegate property to self, which refers to this ViewController.

This is how you can pass values from the first View Controller to the second View Controller.


Next, let's explain the code of the second CommentViewController class.

On line 5, a nullable String property commentText is defined to receive the comment text.

On line 6, a nullable CommentDelegate property commentDelegate is defined to send the comment text back to the first View Controller.


Lines 13 - 16, inside viewDidLoad(), configure the border and appearance of the Text View.

On line 17, the value passed from the first View Controller is set to commentTextView.text.


Lines 20 - 24 are executed when the OK button is tapped.

self.view.endEditing(true) is called to dismiss the keyboard.

Then, delegate?.commentEntered(text: commentTextView.text, cancelled: false) executes the commentEntered() method of the first View Controller, passing the text of commentTextView and false for the cancelled parameter.

Finally, self.dismiss(animated: true) closes this modal screen.


Lines 26 - 30 are executed when the Cancel button is tapped.

This is almost the same as okTapped(), except that delegate?.commentEntered(text: commentTextView.text, cancelled: true) is called, passing true for the cancelled parameter.


When you build and run this, you will have an iOS app that behaves like the demo video.

That's how to pass values between View Controllers using Delegate in Swift.