Push data to other VC with protocol, error: force unwrapped a nil value

Hey guys, my problem:
I have to different VC's with textFields, and I need their text on the third ViewController, I use a two protocols to push the textfield text as data to the third VC.
Here are the two Protocols:
Code Block
protocol RegisterNameProtocol {
    var name: String? { get set }
}
protocol RegisterNumberProtocol {
    var phoneNumber: String? { get set }
}


I implemented the variables in the two vc's and afterwards I tested the functionality with print statements, it worked! Now I need them in the third VC, this is my code yet but it throws the following error: force unwrapped a nil value

The third VC:

Code Block
weak var nameDelegate: RegisterNameProtocol?
weak var phoneDelegate: RegisterNumberProtocol?
    var phoneNumber = ""
    var name = ""
func xyzzy() {
phoneNumber = (phoneDelegate?.phoneNumber)!
        name = (nameDelegate?.name)!
}

I hope someone can help me! Thanks in advance

You don't show enough code to tell for sure.

But writing this is very risky:
Code Block
func xyzzy() {
phoneNumber = (phoneDelegate?.phoneNumber)!
name = (nameDelegate?.name)!
}

Should write:
Code Block
func xyzzy() {
phoneNumber = (phoneDelegate?.phoneNumber) ?? ""
name = (nameDelegate?.name) ?? ""
}


Now to understand why:
  • did VC1 and VC2 conform to the required protocol ?

  • Could you show how you implemented protocol there ?

  • How do you transition from VC1 / VC2 to VC3 ?

  • If you segue, you need to set the delegate in destination (prepare in VC1 / VC2), such as:

Code Block
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? VC3 {phoneDelegate = self
}
}
  • Are VC1 and VC2 still existing when you call from VC3 ? That would be a serious reason for getting nil, if nameDelegate is nil

Notes: if you segue, you don't really need protocols here. Setting a var in the destination directly in prepare should do it.
See the complete logic for delegation here: https://forums.developer.apple.com/thread/111569

So please show complete code.
Well that's all I have, what more do you need to see?

I already tried...
Code Block
phoneNumber = (phoneDelegate?.phoneNumber) ?? ""


That doesn't work because it always takes the alternative data.

I also do not use segues because I don't use storyboards. The first view presents the second View and the second presents the third view.

I already tried...

Code Block
phoneNumber = (phoneDelegate?.phoneNumber) ??

That doesn't work because it always takes the alternative data.
That just proves phoneDelegate is nil.

Could you show your complete code, that will be much easier.

I guess you create in VC1 (and later in VC2) the destination VC (let's call them vc2 and vc3) in code:
Code Block
let vc2 = … // creating vc2 from VC1

then you present vc2.
And do the same in VC2 to create vc3

If so, after creating vc3, set its delegate as needed:
Code Block
vc3.phoneDelegate = self
vc3.nameDelegate = self

In fact, you may have to go in 2 steps: nameDelegate set for vc2 (in VC1) and phoneDelegate set for vc3 in VC2.
Then you would call
Code Block
vc3.phonedelegate?.phoneNumber

and
Code Block
vc3.phonedelegate?.nameDelegate?.name

But once again, please show code, there is too much to guess here.

But there may be simpler ways to do it:
  • create global var for phone and name, that you set in VC1 and VC2 and use in VC3.

  • or carry over the vars:

in VC2 declare
Code Block
var phoneNumber: String?

After you instantiate vc2 in VC1, set the value
Code Block
vc2.phoneNumber = // the value you entered in VC1

in VC3, declare 2 var

Code Block
var phoneNumber: String? // yes, you redeclare here
var name : String?

After you instantiate vc3 (in VC2), set the value
Code Block
vc3.name = // the value you entered in VC2

and carryover the phoneNumber
Code Block
vc3.phoneNumber = self.phoneNumber // you carry over from VC2 to VC3


VC1:
Code Block
class NameVC: UIViewController, RegisterNameProtocol {
    var name: String?
    let vc3 = VerifyPhoneNumberVC()
 override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        vc3.nameDelegate = self
}
@objc func goNext() {
The function which presents vc2
         name = nametextField.text!
        print("Name: \(vc3.Username)")
...
}
}


VC2:

Code Block
class PhoneNumberVC: UIViewController, UITextFieldDelegate, RegisterNumberProtocol {
    var phoneNumber: String?
    let vc3 = VerifyPhoneNumberVC()
override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        vc3.phoneDelegate = self
...
}
func push() {
        phoneNumber = phoneNumberTextField.text!
        print("Number: \(phoneNumber)")
...
}
}


V3:
Code Block
class VerifyPhoneNumberVC: UIViewController {
var nameDelegate: RegisterNameProtocol?
    var phoneDelegate: RegisterNumberProtocol?
    var UserphoneNumber = ""
    var Username = ""
override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        UserphoneNumber = (phoneDelegate?.phoneNumber) ?? ""
        Username = (nameDelegate?.name) ?? ""
        print("Number: \(UserphoneNumber), Name: \(Username)")
}


I think that's all:)
There is something incorrect in class creation:

Code Block
class NameVC: UIViewController, RegisterNameProtocol {
var name: String?
let vc3 = VerifyPhoneNumberVC()


vc3 is not instantiated. So how do you present it ?
You said:

The first view presents the second View and the second presents the third view.
I do not see this anywhere in code.

BTW: your life would me much simpler with storyboard…

The details of this func are very important: please show it
Code Block
@objc func goNext() {
// The function which presents vc2
name = nametextField.text!
print("Name: \(vc3.Username)")
// ...
}



Of course, I thought it would be unnecessary, here I the code:

Code Block
 @objc func goNext() {
         name = nametextField.text!
        print("Name: \(name)")
        
        if nametextField.text?.isEmpty == false {
            let nextVC = PhoneNumberVC()
            nextVC.modalPresentationStyle = .fullScreen
            present(nextVC, animated: true, completion: nil)
        } else {
            print("No valid name")
        }
    }


You dont't load anything in PhoneNumberVC.

Where is the content of PhoneNumberVC defined ? In a nib file ?
You should instantiate nextVC from it.

In addition, you could simplify a little your code:
Code Block
@objc func goNext() {
name = nametextField.text!
print("Name: \(name)")
// if nametextField.text?.isEmpty == false {
if !name.ismpty {
let nextVC = PhoneNumberVC() // That's a problem
nextVC.modalPresentationStyle = .fullScreen
//
present(nextVC, animated: true, completion: nil)
} else {
print("No valid name")
}
}

Push data to other VC with protocol, error: force unwrapped a nil value
 
 
Q