Search code examples
iosswiftdelegatessegue

Delegate is still nil


I am passing user data from a view controller called CreateNewAccount to another view controller called ThanksForJoining. For some reason my delegate is nil. I am using a segue in order to set my vc.delegate to self (= self) and the segue identifier "thanksForJoining" refers to the segue that connects CreateNewAccount to ThanksForJoining on the storyboard. Somehow though, the delegate remains nil.

CreateNewAccount:

import UIKit

protocol UserInfoDelegate {
   func sendUserInfo(firstName: String, lastName: String, username: String, password: String)
}

class CreateNewAccount: UIViewController{
    @IBOutlet weak var FNInput: UITextField!
    @IBOutlet weak var LNInput: UITextField!
    @IBOutlet weak var usernameInput: UITextField!
    @IBOutlet weak var passwordInput: UITextField!

    var infoDelegate: UserInfoDelegate?

    @IBAction func sendInfo(_ sender: Any) {
        if(infoDelegate != nil){
            if(FNInput.text != nil && LNInput.text != nil && usernameInput.text != nil && passwordInput.text != nil){
                let firstName = FNInput.text
                let lastName = LNInput.text
                let username = usernameInput.text
                let password = passwordInput.text

                infoDelegate?.sendUserInfo(firstName: firstName!, lastName: lastName!, username: username!, password: password!)
            }
        }
    }
}

ThanksforJoining:

import UIKit

class ThanksForJoining: UIViewController, UserInfoDelegate {
    @IBOutlet weak var fName: UILabel!

    func sendUserInfo(firstName: String, lastName: String, username: String, password: String) {
        print(firstName)
        fName.text = firstName
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "thanksForJoining") {
            let createNewAccount: CreateNewAccount = segue.destination as! CreateNewAccount
            createNewAccount.infoDelegate = self
        }
    }
}

Solution

  • First of all, you need to confirm that:

    • You connected CreateNewAccount to ThanksForJoining via a segue.

    ViewControllersConnected

    • The segue's Identifier is set to thanksForJoining correctly (Be careful about the letter cases.)

    ConnectingSegue

    If any of the two is not true, you have lost a little time and I have lost my time to prepare for a big typhoon. Update your question to clarify what's happening and wait for someone to help you...


    Assuming two things above, prepare(for:sender:) is called on the source view controller. You need to implement it in your CreateNewAccount class.

    CreateNewAccount:

    import UIKit
    
    class CreateNewAccount: UIViewController {
        @IBOutlet weak var firstNameInput: UITextField!
        @IBOutlet weak var lastNameInput: UITextField!
        @IBOutlet weak var usernameInput: UITextField!
        @IBOutlet weak var passwordInput: UITextField!
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "thanksForJoining" {
                let destinationVC = segue.destination as! ThanksForJoining
                if
                    let firstName = firstNameInput.text, !firstName.isEmpty,
                    let lastName = lastNameInput.text, !lastName.isEmpty,
                    let username = usernameInput.text, !username.isEmpty,
                    let password = passwordInput.text, !password.isEmpty
                {
                    destinationVC.receiveUserInfo(firstName: firstName, lastName: lastName, username: username, password: password)
                }
            }
        }
    }
    

    ThanksForJoining:

    import UIKit
    
    class ThanksForJoining: UIViewController {
        var firstName: String?
    
        @IBOutlet weak var firstNameLabel: UILabel!
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            firstNameLabel.text = firstName
        }
    
        func receiveUserInfo(firstName: String, lastName: String, username: String, password: String) {
            print(firstName)
            self.firstName = firstName
        }
    }
    

    Seems delegate pattern is sort of too much for your purpose and you just need to define a data passing method in the destination view controller ThanksForJoining.

    I assume you have connected your segue from some button of your CreateNewAccount. If the segue is connected from the view controller (not from a button), the code above needs small modification.

    But anyway, in your original code, the method prepare(for:sender:) in ThanksForJoining would never be called, so the delegate would never be set. Thus, the delegate remains nil.