Home > Enterprise >  Protocol Doesn't Send Value to Other VC
Protocol Doesn't Send Value to Other VC

Time:08-19

That is my footerView called FooterTableViewCell. I have this protocol called SurveyAnswerTableViewCellDelegate. It's parent is AddQuestionViewController.

When I tap on the footerView I trigger @IBActtion.

@objc protocol SurveyAnswerTableViewCellDelegate: AnyObject {
    func textSaved(_ text: String)
}

class FooterTableViewCell: UITableViewHeaderFooterView {
var parentVC: AddQuestionViewController!

@IBAction func addNewTapped(_ sender: Any) {
        print("tapped")
        let newTag = model.tag   1
        parentVC.addNewAnswer()
    }

This button action triggers AddQuestionViewController

class AddQuestionViewController: SurveyAnswerViewDelegate, UITextFieldDelegate, UITableViewDelegate, SurveyAnswerTableViewCellDelegate {
    var answers: [SurveyAnswerModel] = []
    var savedText : String = ""
    static var delegate: SurveyAnswerTableViewCellDelegate?

I try creating an empty string and append a new answer to my array. But this text here is always "".

func addNewAnswer() {
        let newAnswer = SurveyAnswerModel(answer: savedText, tag: 0)
        self.answers.append(newAnswer)
        self.tableView.reloadData()
    }
    
    func textSaved(_ text: String) {
         savedText = text
    }

The textfield I try to read is inside SurveyAnswerTableViewCell while setting up the cell inside the tableview I call setup function.

class SurveyAnswerTableViewCell: UITableViewCell {
    @IBOutlet weak var textField: UITextField!
    weak var delegate: SurveyAnswerTableViewCellDelegate?
    var parentVC: AddQuestionViewController!

func setup() {
        if let text = self.textField.text {
            self.delegate?.textSaved(textField.text!)
        }
    }

extension AddQuestionViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as SurveyAnswerTableViewCell
        cell.parentVC = self
        cell.setup()
        return cell
    }

How can I successfully send that text to AddQuestionViewController so it appends a new answer with correct string

CodePudding user response:

There are a few things keeping this from working.

  1. You are calling SurveyAnswerTableViewCell's setup() function directly after dequeuing the cell for reuse. It has not yet (re)appeared on the screen at that point, so the user has not had a chance to enter anything into the text field.
  2. You don't currently set the delegate property of SurveyAnswerTableViewCell to anything, so even if the textfield had valid input, the delegate would be nil and delegate?.textSaved(textField.text!) wouldn't do anything.
  3. Both of the previous points mean that the value of AddQuestionViewController .savedText never gets updated from the empty string. So when addNewAnswer() tries to read it, it will always see that empty string.

Rather than reading the text field when the cell is dequeued, it would make more sense to save the text field value when the user is done typing.

To do that, conform the cell to UITextFieldDelegate and implement the textFieldDidEndEditing(_:) method. From within that method you can then call the delegate method you already have to save the text. Make sure the delegate property on the cell has been set by the VC, or else this won't do anything!

The VC itself should not have a delegate property of type SurveyAnswerTableViewCellDelegate. It serves as the delegate, rather than having one. If this doesn't quite make sense, I would recommend reviewing some online resources on the delegate pattern.

So make sure the ViewController conforms to SurveyAnswerTableViewCellDelegate and then set the cell's delegate value to the VC. The cellForRowAt function should then look something like this:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as SurveyAnswerTableViewCell
    cell.delegate = self
    return cell
}

As a side note, neither the footer nor the cell should have a reference to the parent view controller. as a general rule it is good to avoid subviews being aware of their parent views. Things get unnecessarily complicated when there is two-way knowledge sharing between components, and it makes the subview much less reusable. I would recommend making a delegate for the footer as well, and removing the parentVC property from both the footer and the cell.

CodePudding user response:

Here's what it looks like is happening:

  1. Button tapped
  2. addNewTapped(_:) invoked
  3. addNewAnswer() invoked
  4. newAnswer is appended to answers
  5. tableView.reloadData() invoked
  6. Cells are regenerated with new/empty textfields (so delegate.textSaved is never invoked)

so I'm not sure what you're trying to do, but here's what I figure are a couple possible routes:

  • store UITextFields separately and add them into table cells so they're not removed by a table reload
  • conform AddQuestionViewController to UITextFieldDelegate and set it as the textfields' delegate to observe textfield texts changing (and if you're only using 1 textfield, you could set savedText there)
  • Related