Reputation: 423
I have a UITableView where the section header view contains a UITextField that the user can key in values. When I want to save the value that user keyed in, I need to access the table section header.
I tried using the method headerView(forSection:)
, and I put headerView(forSection: 0)!
as a test to make sure that the section header definitely exists, but every time when I run the programme, the line where the method is returns an error "unexpectedly found nil
while unwrapping an optional value".
I have also tried to tag the UITextField, but when I attempt to access the section header using certainTableView.viewWithTag(_ tag:)
, and cast the resulting UIView to UITextField, there is an error thrown at the line where casting happens, saying "Could not cast value of type 'UITableView' to 'UITextField'."
Both errors look pretty bizarre to me. In the first case, I made sure that the section header is existent, yet the method returned nil
. In the second case, the returned tagged view should be of type UITableViewHeaderFooterView, yet the type is UITableView. Can someone suggest any possible reason why this is so and how to correct?
Or alternatively, is there any better approach to access the section header view so that I can save the text keyed in in the UITextField?
Below is the detail that I used in the first case.
In func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
, I returned a UIView that contains a UITextField. In the table view which I need to save the keyed-in user data, I have a button that, when the user taps it, data are saved. Within that selector, I have the following:
//save item
let a = addItemTableView.headerView(forSection: 0)!
let b = a.subviews[0] as! UITextField
let c = b.text ?? ""
someNSManagedObject.text = c
The error I mentioned above appears at the first line.
Upvotes: 1
Views: 2233
Reputation: 423
After reading the post in this question, I got a hint and found out that, in func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
method, I should return a UITableViewHeaderFooterView instead of the previously UIView. As I changed the returned object's type to UITableViewHeaderFooterView, with everything else remaining the same, (i.e. add a UITextField to the UITableViewHeaderFooterView) I managed to access the UITextField in the UITableViewHeaderFooterView via headerView(forSection:)
method.
To Be even clearer, given in the apple's documentation that the function declaration is func headerView(forSection section: Int) -> UITableViewHeaderFooterView?
, showing that the returned value is UITableViewHeaderFooterView, in order to access the header view using the method, the returned value from func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
should be UITableViewHeaderFooterView instead of any other generic UIView or UIView subclasses.
Hope this helps.
Upvotes: 2
Reputation: 507
First add a property to your model textFieldData
to save textField data in.
Then in your HeaderViewClass
add a closure var textFieldDidChange: ((String) -> Void)?
class HeaderViewClass: UITableViewHeaderFooterView {
// MARK:- IBOutlets
@IBOutlet weak var textField: UITextField!
// MARK:- Variable
var textFieldDidChange: ((String) -> Void)?
// MARK:- Functions
func fill(with model: Model) {
textField.delegate = self
textField.text = model.textFieldData
}
}
extension HeaderViewClass: UITextFieldDelegate {
func textFieldDidChange(_ textField: UITextField) {
textFieldDidChange?(textField.text)
}
}
In your viewController class
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: PlaceOrderFooterView.id) as! PlaceOrderFooterView
footerView.fill(with: models[section])
footerView.textFieldDidChange = { [unowned self] text in
self.models[section].textFieldData = text
}
return footerView
}
Now your model object has the updated value whenever any textField data is changed.
Upvotes: 1
Reputation: 1302
In your method
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {}
when you return your custom header containing UITextField
, assign it's delegate to your controller, this way you'll get all keyed values by user under UITextFieldDelegate
function
Upvotes: 0