4

I want to add to my UITableView some custom section headers, I've searched online and saw that many people are creating a UITableViewCell subclass and registering that as a header, it sounds like a bad practice since there's a specific class for headers and footers called UITableViewHeaderFooterView.

So I tried to do it myself, I've created a xib file and a UITableViewHeaderFooterView subclass- called SelectedProductsSectionHeader.

Here's how I've connected my outlets enter image description here enter image description here enter image description here

Here's the relevant code on the UITableViewController side-

override func viewDidLoad() {
    super.viewDidLoad()

    let selectedProductsSectionHeaderNib = UINib(nibName: "SelectedProductsSectionHeader", bundle: nil)
    tableView.register(selectedProductsSectionHeaderNib, forHeaderFooterViewReuseIdentifier: "selectedProductsHeader")
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    if section == SectionIndex.selectedProducts{

        let selectedProductsHeaderCell = tableView.dequeueReusableHeaderFooterView(withIdentifier: "selectedProductsHeader") // throws error
        guard let selectedProductsHeader = selectedProductsHeaderCell as? SelectedProductsSectionHeader else { return nil }

        return selectedProductsHeader
    }

    return nil
}

Runtime error:

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key label.'

So I tried something else, instead of setting the File's Owner to my custom class, I've set View to my custom class, and it worked.

enter image description here enter image description here enter image description here

My question is why it didn't work on the first method? Am I using File's Owner as I should? If not- How am I supposed to use it?

Niv
  • 517
  • 5
  • 18
  • Try register class [myTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"CustomHeaderView"]; – levin varghese Dec 06 '18 at 11:48
  • Try with separate xib for each cell – SPatel Dec 06 '18 at 13:20
  • Yes, it's a bit confusing. When you register a NIB for reuse, the system uses the XIB's / NIB's *content* - not the file itself. So, as you've seen, the proper way to do this is to set the XIB's root view to your custom class. – DonMag Dec 06 '18 at 13:27
  • @levinvarghese I'm not sure how it supposed to work with a XIB file, how the outlets should connect? I've tried it and got an error who states my outlets are nil – Niv Dec 06 '18 at 14:07
  • @SPatel I'm not sure what you meant by "separate xib for each cell" – Niv Dec 06 '18 at 14:08
  • @DonMag You're saying that I should never touch the "File's Owner? or you're relating specifically to `UITableVieHeaderFooterView`? – Niv Dec 06 '18 at 14:12
  • It depends on how you're using the XIB ... if you are using a class where you are instantiating the "first view" (common method of loading xib contents), then the xib File's Owner should be your class. When using tableView.register(nib...), then the xib's ***view*** should be your class, and the xib's File's Owner should be blank (defaults to NSObject, I believe). – DonMag Dec 06 '18 at 14:28

1 Answers1

0

This is a great question. The reason it doesn't work when you set the class on the view itself is that it doesn't have exactly one child view. Whenever you want to make the root view a subclass, you need to add one more container view as a loaded nib expects a parent view.

All you need to do is set the class to the root view, drag in a container view and constrain it to all edges of the superview then add your child views and it will work.

M3nd3z
  • 316
  • 2
  • 12