We do have a TableViewModel which is implementing the UITableViewDelegate and the UITableViewDataSource.  It holds the sections and returns the right rows and elements of our UITableViews.
Now we want to have a custom table view section footer. Therefor we implement the optional public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? so that this returns a UIView from a xib file. This is all fine but it ends up in a wrong footer height. If we use func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? the footer is displayed correct and the height of the footer is set correct. 
So we also have to implement the optional public func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat or the optional public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
- Question: How do i get the height of an UIView which this was instantiated? view.frame.boundsorview.frame.heightis always 0.
- Question: What is the default value Apple uses for the footer and how does it calculate that? I recognised that if we return table.sectionFooterHeightfor the default (not our custom footer view) the hight is correct.
TableViewModel:
class TableViewModel: NSObject, UITableViewDelegate, UITableViewDataSource {
    var sections: [TableViewSection] = []
    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].numberOfRowsInTableView(tableView)
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return sections[(indexPath as NSIndexPath).section].tableView(tableView, cellForRowAtIndexPath: indexPath)
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        sections[(indexPath as NSIndexPath).section].tableView(tableView, didSelectRowAtIndexPath: indexPath)
    }
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sections[section].headerText
    }
    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        sections[section].tableView(tableView, willDisplayHeaderView: view)
    }
    func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
        return sections[section].footerText
    }
    func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
        sections[section].tableView(tableView, willDisplayFooterView: view)
    }
    func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
        return sections[(indexPath as NSIndexPath).section].tableView(tableView, cellContentsToCopyAtIndexPath: indexPath, withSender: nil) != nil
    }
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        ??
    }
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        return sections[section].footerView
    }
    func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
        ??
    }
}
 
     
    