4

Consider two view controller Controller1 and Controller2, I have created a form of many UITextField in controller 1, in that when a user clicks a particular UITextField it moves to Controller2 and he selects the data there.

After selecting the data in Controller2 it automatically moves to Controller1, while returning from controller2 to controller1 other UITextfield data got cleared and only the selected data from controller2 is found. I need all the data to be found in the UITextfield after selecting.

Here is the code for returning from Controller2 to Controller1

 if(Constants.SelectedComplexName != nil)
  {
      let storyBoard: UIStoryboard = UIStoryboard(name: "NewUserLogin", bundle: nil)
      let newViewController = storyBoard.instantiateViewController(withIdentifier: "NewUser") as! NewUserRegistrationViewController
      self.present(newViewController, animated: true, completion: nil)
   }
Syed Qamar Abbas
  • 3,637
  • 1
  • 28
  • 52
KARTHICK T M
  • 75
  • 1
  • 8
  • add your VC1 Code and how will you pop from VC2 to VC1 – Anbu.Karthik Oct 05 '18 at 13:00
  • @Anbu.karthik my VC1 code let storyBoard: UIStoryboard = UIStoryboard(name: "NewUserLogin", bundle: nil) let newViewController = storyBoard.instantiateViewController(withIdentifier: "ComplexList") as! ComplexSearchViewController self.present(newViewController, animated: true, completion: nil) – KARTHICK T M Oct 05 '18 at 13:05
  • You may want to use an unwind segue. Please see https://stackoverflow.com/questions/35313747/passing-data-with-unwind-segue – Mike Taverne Oct 05 '18 at 14:30
  • *only the selected data from controller2 is found* - How you are fetching the data from controller2 to controller1? – Ankit Jayaswal Oct 05 '18 at 14:38

3 Answers3

1

To pass messages you need to implement Delegate.

protocol SecondViewControllerDelegate: NSObjectProtocol {
    func didUpdateData(controller: SecondViewController, data: YourDataModel)
}
//This is your Data Model and suppose it contain 'name', 'email', 'phoneNumber'
class YourDataModel: NSObject {
    var name: String? //
    var phoneNumber: String?
    var email: String?
}
class FirstViewController: UIViewController, SecondViewControllerDelegate {
    var data: YourDataModel?
    var nameTextField: UITextField?
    var phoneNumberTextField: UITextField?
    var emailTextField: UITextField?

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

    func callWebApi() {
        //After Success Fully Getting Data From Api
        //Set this data to your global object and then call setDataToTextField()
        //self.data = apiResponseData
        self.setDataToTextField()
    }

    func setDataToTextField() {
        self.nameTextField?.text = data?.name
        self.phoneNumberTextField?.text = data?.phoneNumber
        self.emailTextField?.text = data?.email
    }

    func openNextScreen() {
        let vc2 = SecondViewController()//Or initialize it from storyboard.instantiate method
        vc2.delegate = self//tell second vc to call didUpdateData of this class.
        self.navigationController?.pushViewController(vc2, animated: true)
    }

    //This didUpdateData method will call automatically from second view controller when the data is change
    func didUpdateData(controller: SecondViewController, data: YourDataModel) {

    }
}
class SecondViewController: UIViewController {
    var delegate: SecondViewControllerDelegate?

    func setThisData(d: YourDataModel) {
        self.navigationController?.popViewController(animated: true)
        //Right After Going Back tell your previous screen that data is updated.
        //To do this you need to call didUpdate method from the delegate object.
        if let del = self.delegate {
            del.didUpdateData(controller: self, data: d)
        }
    }
}
Syed Hasnain
  • 130
  • 1
  • 8
0
push your view controller instead of a present like this  


if(Constants.SelectedComplexName != nil)
 {
    let storyBoard: UIStoryboard = UIStoryboard(name: "NewUserLogin", bundle: nil)
    let newViewController = storyBoard.instantiateViewController(withIdentifier: "NewUser") as! NewUserRegistrationViewController
    self.navigationController?.pushViewController(newViewController, animated: true)
 }

and then pop after selecting your data from vc2 like this

self.navigationController?.popViewController(animated: true)

and if you are not using navigation controller then you can simply call Dismiss method

self.dismiss(animated: true) {
    print("updaae your data")
}
Mahesh Dangar
  • 806
  • 5
  • 11
  • This is a good explanation of how to push/pop, but does not show how the data entered on VC2 will be returned for display in VC1. – Mike Taverne Oct 05 '18 at 14:28
0

There are a few ways to do it, but it usually depends on how you move from VC#1 to VC#2 and back.

(1) The code you posted implies you have a Storyboard with both view controllers. In this case create a segue from VC#1 to VC#2 and an "unwind" segue back. Both are fairly easy to do. The link provided in the comments does a good job of showing you, but, depending on (1) how much data you wish to pass back to VC#1 and (2) if you wish to execute a function on VC#2, you could also do this:

VC#1:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "ShowVC2" {
        if let vc = segue.destination as? VC2ViewController {
            vc.VC1 = self
        }
    }
}

VC#2:

weak var VC1:VC1ViewController!

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if isMovingFromParentViewController {
        VC1.executeSomeFunction()
    }
}

Basically you are passing the entire instance of VC1 and therefore have access to everything that isn't marked private.

(2) If you are presenting/dismissing VC#2 from VC#1, use the delegate style as described by one of the answers.

VC#1:

var VC2 = VC2ViewController()

extension VC1ViewController: VC2ControlllerDelegate {
    func showVC2() {
        VC2.delegate = self
        VC2.someData = someData
        present(VC2, animated: true, completion: nil)
    }
    function somethingChanged(sender: VC2ViewController) {
        // you'll find your data in sender.someData, do what you need
    }
}

VC#2:

protocol VC2Delegate {
    func somethingChanged(sender: VC2ViewController) {
        delegate.somethingChanged(sender: self)
    }
}
class DefineViewController: UIViewController {

    var delegate:DefineVCDelegate! = nil
    var someData:Any!

    func dismissMe() {
        delegate.somethingChanged(sender: self)
        dismiss(animated: true, completion: nil)
    }
}

}

Basically, you are making VC#1 be a delegate to VC2. I prefer the declaration syntax in VC#2 for `delegate because if you forget to set VC#1 to be a delegate for VC#2, you test will force an error at runtime.