Search code examples
iosswiftdelegatesencapsulationaccess-modifiers

How to prevent accessing delegate methods for other classes?


For the purpose of making a "more encapsulated" app, I am trying to specify the access levels for my view controllers properties/methods. But the issue is when trying to private a datasource/delegate method, I am getting a compile-time error complaining about it.

For instance, I have two view controllers: ViewControllerA and ViewControllerB, the first one implements the table view datasource method and privateWork() private method, as follows:

class ViewControllerA: UIViewController, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 101
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell")!
        return cell
    }

    private func privateWork() {
        print(#function)
    }
}

And the second view controller has an instance of ViewControllerA -in a method called setupViewControllerA()- as follows:

class ViewControllerB: UIViewController {
    func setupViewControllerA() {
        // in real case, you should get it from its stroyborad,
        // this is only for the purpose of demonstrating the issue...
        let vcA = ViewControllerA()

        vcA.privateWork()
    }
}

When implementing vcA.privateWork() it gives a compile-time error:

'privateWork' is inaccessible due to 'private' protection level

which is so appropriate! I want to prevent the accessing of vcA.privateWork() for other classes.

My issue is: simply, I want to do the same behavior for the datasource methods, so if I tried to implement:

private func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 101
}

I getting a compile time error:

Method 'tableView(_:numberOfRowsInSection:)' must be as accessible as its enclosing type because it matches a requirement in protocol 'UITableViewDataSource'

with a fix suggestion to let private to be internal. It leads to let the following code (in the second view controller):

vcA.tableView(..., numberOfRowsInSection: ...)

to be valid, which is inappropriate, there is no need to let such a datasource method to be accessible from outside of its class.

What should I do for such a case?


Solution

  • Make table view adapter that conforms to UITableViewDataSource and UITableViewDelegate and add it as private property to your view controller:

    final class TableViewAdapter: NSObject, UITableViewDataSource, UITableViewDelegate {
    
        // Implementation of protocol methods
    
    }
    
    
    
    class ViewControllerA: UIViewController {
    
        private let adapter = TableViewAdapter()
    
        @IBOutlet private var tableView: UITableView! {
            didSet {
                tableView.delegate = adapter
                tableView.dataSource = adapter
            }
        }
    
    }