swiftuitableviewuiviewcontrolleruitableviewsectionheader

Unable to Format the Section Header of UITableView


One View Controller which has three Table Views in it. I am struggling with formatting and setting the section header for each table.My func for viewForHeaderInSection is attached below

My Goal is to achieve something like the image. Struggling to format and design the section header for each of the table views. Using the attached code get the Terminating app due to uncaught exception 'CALayerInvalid', reason: 'layer <CALayer: 0x12cc80610> is a part of cycle in its layer tree' error message

enter image description here

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
       if(tableView == firstTableView){
        let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
           button.tag = section
           button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
           button.addTarget(self,action:#selector(buttonClicked),for:.touchUpInside)
        let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
        view.addSubview(button)
        let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
        label.font = UIFont.systemFont(ofSize: 24)
        label.textColor = .white
        label.text = "Learn More"
        view.addSubview(label)
        view.backgroundColor = UIColor.gray // Set your background color
       }

        else if (tableView == secondTableView) {
            let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
                     button.tag = section
                     button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
                     button.addTarget(self,action:#selector(buttonClickedSecond),for:.touchUpInside)
                  let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
                  view.addSubview(button)
                  let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
                  label.font = UIFont.systemFont(ofSize: 24)
                  label.textColor = .white
                  label.text = "Get Support"
                  view.addSubview(label)
                  view.backgroundColor = UIColor.gray
        }
        else if (tableView == thirdTableView)
       {
        let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
                            button.tag = section
                            button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
                            button.addTarget(self,action:#selector(buttonClickedThird),for:.touchUpInside)
                         let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
                         view.addSubview(button)
                         let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
                         label.font = UIFont.systemFont(ofSize: 24)
                         label.textColor = .white
                         label.text = "Community"
                         view.addSubview(label)
                         view.backgroundColor = UIColor.gray
        }

        return view
    }

Any help and assistance will be appreciated. Thanks!


Solution

  • In your viewForHeaderInSection func, you are creating a UIView object named view inside each if block. At the end of each if block, that object goes out-of-scope... it no longer exists.

    Xcode doesn't give you a warning or error on this line:

    return view
    

    because view is an existing object of your controller.

    This is one of the reasons it's a bad practice to use "built-in" object names for variables you are creating.

    Change the top of your func to this:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
        let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
    
        if(tableView == firstTableView){
            // etc...
    

    and remove that line from within each of your if blocks.

    Better yet, change it to something like:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
        let myHeaderView = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
    
        if(tableView == firstTableView){
            // etc... but change all instances of view. to myHeaderView.
    
        } // end of last if block
    
        return myHeaderView
     }