8 Replies
      Latest reply on Jul 13, 2018 2:39 AM by alexfromhome
      alexfromhome Level 1 Level 1 (0 points)

        Hello,

        I'm a beginner with Swift and I'm struggling to understand the way the variables are send between page_1  and page_2 using delegate and protocols.

         

         

        I have a 2-page application: ViewController1.swift and ViewController2.swift

        - on page 1 (ViewController1.swift) I have a textbox (TextBoxControl)  and a button.

        - on page 2 (ViewController2.swift) I have a label and a button

         

         

        I want to send text in thextbox from page_1 to page_2 and print it in page_2.

         

         

        The problem is that the delegated is always nil (it prints on the console

        ... print ("Delegate is nil"). )

         

        Technologies: XCODE Version 9.4.1, swift 4

         

        How can I solve this?

         

         

        Thanks in advance.

         

         

         

        CODE - page1 ( ViewController1 ):


        import UIKit

        protocol delegate_transmisie_date_1_2{
             func transmisie(text1: String)
        }

        class ViewController1: UIViewController {
             var delegate: delegate_transmisie_date_1_2?

             @IBOutlet weak var text1: UITextField!
            
             @IBAction func btn_Send_Date_Using_DelegateAndProtocol(_ sender: Any) {
                 if self.delegate != nil {
                     self.delegate?.transmisie(text1: text1.text!)
                 }else{
                     print("Delegate is nil")
                 }
                
                 let selectionView = storyboard?.instantiateViewController(withIdentifier: "ID_PAGE2") as! ViewController2      

                present(selectionView, animated: true, completion: nil)
                
             }
             override func viewDidLoad() {
                 super.viewDidLoad()
                 // Do any additional setup after loading the view, typically from a nib.
                
                    }


        }

         

         

        CODE - PAGE2 ( ViewController2 )


        import UIKit

        class ViewController2: UIViewController, delegate_transmisie_date_1_2 {
            
            
             @IBOutlet weak var label1: UILabel!

            
             func transmisie(text1: String, text2: String) {
               
                 label1.text = text1
             }
            
             @IBAction func btn_CloseWindow(_ sender: Any) {
                 dismiss(animated: true, completion: nil)
             }

            override func viewDidLoad() {
                 super.viewDidLoad()
                
                 //This is the place where the delegate must by set ?????

                let pagina1 = storyboard?.instantiateViewController(withIdentifier: "ID_PAGINA1") as! ViewController1
                 pagina1.delegate = self
               
             }

             override func didReceiveMemoryWarning() {
                 super.didReceiveMemoryWarning()
                 // Dispose of any resources that can be recreated.
             }
            
        }

        • Re: Sending data between viewControllers using protocol+delegate in swift 4
          Claude31 Level 7 Level 7 (4,325 points)

          Please show your code where you define and use delegate.

           

          But using delegates may not be the simplest way to transfer data between viewControllers ; there is a simple way to do this :

          - you have a segue from initialVC (ViewController1) to destVC (destination)

          - destVC is a subclass of UIViewController, ViewController2

          - you have given it an identifier, such as TransferSegue

          - in ViewController2, you have a property to receive the text to pass

          var textToReceive = ""

           

          - in ViewController1, you have a prepare for segue func where you set the parameter to pass

           

              override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                  if segue.identifier == "TransferSegue" {
                      if let destVC = segue.destination as? ViewController2 {
                         destVC.textToReceive = TextBoxControl.text
                    }
                  }
               }

           

          - in ViewController2, you have defined a UILabel IBOutlet

          @IBOutlet weak var label: UILabel!

           

          - in ViewController2, in viewDidLoad, you use textToReceive to set the label

          label.text = textToReceive
          • Re: Sending data between viewControllers using protocol+delegate in swift 4
            alexfromhome Level 1 Level 1 (0 points)

            Thanks Claude31, but my issue is other: i have just updated my source code to see. I think that is not properly set the delegate.

              • Re: Sending data between viewControllers using protocol+delegate in swift 4
                Claude31 Level 7 Level 7 (4,325 points)

                There are several errors, BUT anyway, you create a new instances of view controllers, so you loose reference to what exist already.

                 

                Errors:

                In class ViewController2: UIViewController

                you define pagina1, but inside viewDidLoad : it disappears as soon as you leave the function.

                 

                Could declare at the top level of the class, outside any func.

                var pagina1 : ViewController1?

                 

                That would change viewDidLoad:

                    override func viewDidLoad() {
                         super.viewDidLoad()
                         //This is the place where the delegate must by set ?????
                         pagina1 = storyboard?.instantiateViewController(withIdentifier: "ID_PAGINA1") as! ViewController1
                         pagina1?.delegate = self
                     }

                 

                In addition,

                     func transmisie(text1: String, text2: String) {
                         label1.text = text1
                     }

                 

                does not conform to protocol definition.

                 

                Should be

                 

                     func transmisie(text1: String) {
                         label1.text = text1
                     }

                 

                But, once again,

                - either you define persistent references of the viewControllers and use them (then delegate is not very useful)

                - or it is simpler here to use a segue.

                  • Re: Sending data between viewControllers using protocol+delegate in swift 4
                    alexfromhome Level 1 Level 1 (0 points)

                    thanks, but i stil get the same error: "Delegate is nil"

                     

                    My Final Code:

                     

                     

                     

                     

                    //  ViewController.swift

                    import UIKit

                     

                    protocol delegate_transmisie_date_1_2{

                        func transmisie(text1: String, text2: String)

                     

                    }

                     

                    class ViewController: UIViewController {

                        var delegate: delegate_transmisie_date_1_2!

                     

                        @IBOutlet weak var text2: UITextField!

                        @IBOutlet weak var text1: UITextField!

                     

                        @IBAction func btn_TrimiteDate_DElegate(_ sender: Any) {

                     

                            if self.delegate != nil {

                                self.delegate.transmisie(text1: "alex", text2: "alex2")

                              

                            }else{

                                print("Delegate is nil")

                            }

                      

                      

                            let selectionView = storyboard?.instantiateViewController(withIdentifier: "ID_PAGINA2") as! ViewController_pagina2

                      

                            present(selectionView, animated: true, completion: nil)

                     

                        }

                        override func viewDidLoad() {

                            super.viewDidLoad()

                            // Do any additional setup after loading the view, typically from a nib.

                      

                               }

                    }

                     

                     

                     

                     

                    //  ViewController_pagina2.swift

                     

                    import UIKit

                     

                    class ViewController_pagina2: UIViewController, delegate_transmisie_date_1_2 {

                     

                        var pagina1 : ViewController?

                     

                        @IBOutlet weak var label1: UILabel!

                        @IBOutlet weak var label2: UILabel!

                     

                        func transmisie(text1: String, text2: String) {

                            label1.text = text1

                            label2.text = text2

                        }

                     

                        @IBAction func btn_Inchide(_ sender: Any) {

                            dismiss(animated: true, completion: nil)

                        }

                        override func viewDidLoad() {

                            super.viewDidLoad()

                      

                            pagina1 = storyboard?.instantiateViewController(withIdentifier: "ID_PAGINA1") as! ViewController

                            pagina1?.delegate = self

                     

                        }

                    }

                      • Re: Sending data between viewControllers using protocol+delegate in swift 4
                        Claude31 Level 7 Level 7 (4,325 points)

                        The problem is that the delegate is set for pagina1, the new ViewController1 instance you create,

                            override func viewDidLoad() {
                                super.viewDidLoad()
                           
                                pagina1 = storyboard?.instantiateViewController(withIdentifier: "ID_PAGINA1") as! ViewController
                                pagina1?.delegate = self
                            }

                         

                        not for the one from which you have called btn_Send_Date_Using_DelegateAndProtocol ; for this one, delegate is still nil !

                         

                        Have a look here to see how to use delegate along with a segue,

                        h ttps://medium.com/ios-os-x-development/pass-data-with-delegation-in-swift-86f6bc5d0894

                         

                        delegate is set in the prepare for segue, so that can work.

                          • Re: Sending data between viewControllers using protocol+delegate in swift 4
                            alexfromhome Level 1 Level 1 (0 points)

                            Ok, the problem is clear, but,  I don't know how can modify my code.  

                              • Re: Sending data between viewControllers using protocol+delegate in swift 4
                                Claude31 Level 7 Level 7 (4,325 points)

                                Did you try to follow step by step what is described in the link ?

                                 

                                h ttps://medium.com/ios-os-x-development/pass-data-with-delegation-in-swift-86f6bc5d0894

                                 

                                Essentially :

                                - create a segue between the 2 controllers

                                - remove all the instantiateViewController

                                - in prepare for segue, you set the delegate

                                 

                                In fact, it will work differently :

                                - you will get data from lhe text field of VC1 when you tap a button in VC2,

                                - if you just want to pass data from VC1 to VC2 when you tap button in VC1, this should be done in the prepare for segue

                                 

                                Here is the code

                                 

                                First embed ViewController1 in a navigation controller (with XCode menu Editor -> Embed in -> Navigation controller

                                - That will provide a return button from VC2

                                 

                                // FOR ViewController1

                                You have 2 objects :

                                a textField text1

                                a button connected to btn_Send_Date_Using_DelegateAndProtocol

                                plus a segue to VC2, named VCInitialToVCFinal : control-drag from the button at the very top left of ViewController1 windowController to ViewController2 and select show

                                 

                                import UIKit
                                
                                protocol delegate_transmisie_date_1_2{
                                    func transmisie() -> String
                                }
                                
                                class ViewController1: UIViewController, delegate_transmisie_date_1_2 {
                                
                                    @IBOutlet weak var text1: UITextField! 
                                  
                                    @IBAction func btn_Send_Date_Using_DelegateAndProtocol(_ sender: Any) {   // should better be called performedSegue 
                                      
                                        performSegue(withIdentifier: "VCInitialToVCFinal", sender: nil)
                                    }
                                
                                
                                    override func viewDidLoad() {
                                        super.viewDidLoad()
                                        // Do any additional setup after loading the view, typically from a nib.
                                    }
                                
                                     // Protocol implementation
                                    func transmisie() -> String {
                                      
                                        return text1.text!
                                    }
                                
                                     // Segue : we set the delegate
                                    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
                                        if let destination = segue.destination as? ViewController2 {
                                            destination.delegate = self
                                        }
                                    }
                                }

                                 

                                // For ViewController2

                                You have 2 objects

                                - a button, connected to getDataFromIntial

                                - a label label1

                                 

                                import UIKit
                                
                                class ViewController2: UIViewController {
                                      
                                    var delegate: delegate_transmisie_date_1_2?
                                   
                                    @IBOutlet weak var label1: UILabel!          // A label where we write data we get from VC1 when we tap the button
                                   
                                    @IBAction func getDataFromInitial(_ sender: UIButton) {     // IBAction for a button in VC2, named get data from VC1
                                       
                                        let testReadFromVC1 = delegate?.transmisie()
                                        label1.text = testReadFromVC1
                                    }
                                   
                                    override func viewDidLoad() {
                                        super.viewDidLoad()
                                       
                                    }
                                   
                                }

                                 

                                How to use :

                                 

                                in VC1, type some text in the text field : "This will be read later from VC2"

                                Then click on the button in VC1

                                VC2 shows through the segue

                                Tap on the button in VC2

                                Then the text you typed in VC1 dispalys in the label

                                 

                                You have effectively transfered data fromVC1 to VC2 through the delegation.

                                 

                                You can also write from ViewController2 to ViewController1 (which now exist when we are in VC2). This is probably more what you are looking for.

                                 

                                Complement protocol:

                                 

                                protocol delegate_transmisie_date_1_2{
                                    func transmisie() -> String
                                   
                                    func writeInVC1(text: String)
                                }

                                 

                                // In ViewController1

                                add this

                                    func writeInVC1(text: String) {
                                       
                                        text1.text = text
                                    }

                                 

                                 

                                // In ViewController2

                                add this

                                     a button "Transfer" connected to an IBAction

                                     an IBOutlet for a textField

                                    @IBOutlet weak var textFieldToTransfer: UITextField!

                                 

                                    @IBAction func writeDataToVC1(_ sender: UIButton) {     // For Transfer button
                                       
                                        let textToWrite = textFieldToTransfer.text!
                                        delegate?.writeInVC1(text: textToWrite)
                                    }