qsmy
qsmy

Reputation: 423

Accessing UITableView Header View

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

Answers (3)

qsmy
qsmy

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

Soufian Hossam
Soufian Hossam

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

Arslan Asim
Arslan Asim

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

Related Questions