Search code examples
iosswiftuitableviewseguensuserdefaults

Is there an alternative to ViewDidLoad? Any other place to write code which needs to be activated, when a viewController loads?


I have a viewController which holds three text fields. Each text field is connected to a label and uses NSUser Default so that when a user writes something in the textfield, the text is saved with a key - and showed in the label assigned to it. That works fine.

Two of the three text field are for the user to write "a question" and an "extra identifier". In case the user don't know what to write in these, in the top of the screen there are two buttons leading to two different tableViewControllers - both of which holds tableViews with inspiration/options that the user can choose. I implemented a segue from each, so that when the user taps a tableViewCell, the text in this cell is passed to the right textfield in viewController1 - and the user can now press save and save this text in the NSUser Default and let it be shown in the assigned label.

The problem is that these segues are ofcourse using ViewDidLoad to show the passed text from the inspiration tableViews. This means that when you enter the second tableViewController with inspiration after saving you chosen "question" from the first, then - because of the viewDidLoad method - all textfields and labels are cleared again and only the thing you just passed in there is shown... So:

Can I use another method than viewDidLoad to pass the data into ViewController1?

Or can I maybe add some code to the viewDidLoad method, so that it stops "resetting" all labels and textfields every time you enter the viewController?

Or do I need to go about it all a completely different way?

I hope it all makes sense - sorry about the long explanation! :D

Here's the relevant code from viewController1:

var chosenQuestion:String = ""
var chosenIdentifier:String = ""

override func viewDidLoad() {
    super.viewDidLoad()
DiaryQuestionTextField.text = chosenQuestion
RandomIdentifierTextField.text = chosenIdentifier
}


@IBAction func WriteDiaryName() {

    let title = "You have now chosen you diary's name. \n \n Do you wish to save this name and continue? \n \n You can always change all the details."
    let alert =  UIAlertController(title: title, message: nil, preferredStyle: .alert)

    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))

    alert.addAction(UIAlertAction(title: "Save", style: .default, handler: { action in
        self.defaults.setValue(self.DiaryNameTextField.text, forKey: "DiaryNameKey")
        let NewDiaryName = self.defaults.string(forKey: "DiaryNameKey")
        self.DiaryNameLabel.text = NewDiaryName

    }))
        present(alert, animated: true, completion: nil)
    }

And there is ofcourse two similar methods for "WriteQuestion" and "WriteExtraIdentifier".

And here's the relevant code from one of the two tableViewControllers with "inspiration":

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if segue.destination is UpdatingIdentifiers {
        let vc = segue.destination as? UpdatingIdentifiers
        let selectedRowIndex = self.tableView.indexPathForSelectedRow
        let cell = self.tableView.cellForRow(at: selectedRowIndex!)
        let label = cell?.viewWithTag(420) as! UILabel
        vc?.chosenQuestion = label.text!
    }
}

Thanks!

enter image description here

enter image description here


Solution

  • You can simply use a closure approach for this scenario.

    1. Create a closure variable in ViewController2.
    2. Set the value of this closure whenever you present ViewController2 from ViewController1.
    3. Call the closure whenever you select a row in tableView of ViewController2 and pass the selected value in the closure.
    4. Update the chosenQuestion whenever you get a new value from closure using which in turn will update the textField's value using the property observer.

    Example Code:

    class ViewController1: UIViewController
    {
        @IBOutlet weak var DiaryQuestionTextField: UITextField!
    
        var chosenQuestion = "" {
            didSet{
                //Textfield will be updated everytime a new value is set in chosenQuestion variable
                self.DiaryQuestionTextField.text = self.chosenQuestion
            }
        }
    
        @IBAction func showInspirationVC(_ sender: UIButton)
        {
            let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
            controller.handler = {[weak self](data) in
                self?.chosenQuestion = data
            }
            self.present(controller, animated: true, completion: nil)
        }
    }
    
    class ViewController2: UIViewController, UITableViewDelegate, UITableViewDataSource
    {
        var handler: ((String)->())?
        var data = ["Question-1", "Question-2", "Question-3", "Question-4", "Question-5"]
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
        {
            return self.data.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
        {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
            cell.textLabel?.text = self.data[indexPath.row]
            return cell
        }
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
        {
            self.dismiss(animated: true) {
                self.handler?(self.data[indexPath.row])
            }
        }
    }
    

    Storyboard:

    enter image description here

    Try implementing a simple use case first. And you don't need segues in this approach since you are presenting the controller programatically.

    Let me know in case of any issue.