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.
- You are calling
SurveyAnswerTableViewCell
'ssetup()
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. - You don't currently set the delegate property of
SurveyAnswerTableViewCell
to anything, so even if the textfield had valid input, the delegate would benil
anddelegate?.textSaved(textField.text!)
wouldn't do anything. - Both of the previous points mean that the value of
AddQuestionViewController .savedText
never gets updated from the empty string. So whenaddNewAnswer()
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:
- Button tapped
addNewTapped(_:)
invokedaddNewAnswer()
invokednewAnswer
is appended toanswers
tableView.reloadData()
invoked- 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
UITextField
s separately and add them into table cells so they're not removed by a table reload - conform
AddQuestionViewController
toUITextFieldDelegate
and set it as the textfields' delegate to observe textfield texts changing (and if you're only using 1 textfield, you could setsavedText
there)