Search code examples
iosswiftprotocolsmultiple-inheritance

UIViewController multiple inheritance


I have a class called BaseViewController which contains a function where I can add a header to my VC and anchor it

class BaseViewController: UIViewController {

    let headerView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.green
        return view
    }()

    func addHeader() { 
        view.addSubview(headerView)
        // then anchor it to top
    }

}

I have another class called ScrollViewController which adds a scrollViewController to my VC and anchors it

class ScrollViewController: UIViewController {

    let scrollView: UIScrollView = {
        let view = UIScrollView()
        view.backgroundColor = UIColor.green
        return view
    }()

    func addScrollView() { 
        view.addSubview(scrollView)
        // then anchor it to top
    }

}

Finally my main class HomeViewController wants to have both a header and a scrollView so I inherit from both like this:

class HomeViewController: ScrollViewController, BaseViewController {

    override viewDidLoad() {
        super.viewDidLoad()

        addScrollView()
        addHeaderView()

        let view = UIView()
        //anchor view to bottom of the header
    }
}

However swift doesn't allow multiple inheritance so I tried using protocols and extensions which works but the problem is that I want other views to be able to be anchored to the header and scrollView so it didn't fit my needs.

What could I do so I can implement something like that

Thanks


Solution

  • Swift does not support multiple inheritance. However, protocols and protocol extensions can accomplish what you want.

    Example:

    protocol HeaderProtocol {
        func addHeaderView() -> UIView
    }
    
    extension HeaderProtocol where Self: UIViewController {
        func addHeaderView() -> UIView {
            let headerView = UIView()
            headerView.backgroundColor = UIColor.green
            view.addSubview(headerView)
            // then anchor it to top
    
            return headerView
        }
    }
    
    protocol ScrollViewProtocol {
        func addScrollView() -> UIView
    }
    
    extension ScrollViewProtocol where Self: UIViewController {
        func addScrollView() -> UIView {
            let scrollView = UIScrollView()
            scrollView.backgroundColor = UIColor.green
            view.addSubview(scrollView)
            // then anchor it to top
    
            return scrollView
        }
    }
    
    class HomeViewController: UIViewController, ScrollViewProtocol, HeaderProtocol {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let scrollView = addScrollView()
            let headerView = addHeaderView()
        }
    }
    

    Alternative approach:

    protocol HeaderProtocol {
        var headerView: UIView? { get set }
        func addHeaderView() -> UIView
    }
    
    extension HeaderProtocol where Self: UIViewController {
        func addHeaderView() -> UIView {
            let headerView = UIView()
            headerView.backgroundColor = UIColor.green
            view.addSubview(headerView)
            // then anchor it to top
    
            return headerView
        }
    }
    
    protocol ScrollViewProtocol {
        var scrollView: UIView? { get set }
        func addScrollView() -> UIView
    }
    
    extension ScrollViewProtocol where Self: UIViewController {
        func addScrollView() -> UIView {
            let scrollView = UIScrollView()
            scrollView.backgroundColor = UIColor.green
            view.addSubview(scrollView)
            // then anchor it to top
    
            return scrollView
        }
    }
    
    class HomeViewController: UIViewController, ScrollViewProtocol, HeaderProtocol {
        var scrollView: UIView?
        var headerView: UIView?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            scrollView = addScrollView()
            headerView = addHeaderView()
        }
    }