如何防止访问其他类的委托方法?

时间:2018-02-13 09:04:06

标签: ios swift delegates encapsulation access-modifiers

为了制作一个"更多encapsulated" app,我正在尝试为视图控制器属性/方法指定访问级别。但问题是在尝试private数据源/委托方法时,我收到了一个抱怨它的编译时错误。

例如,我有两个视图控制器:ViewControllerAViewControllerB,第一个实现表视图数据源方法和privateWork()私有方法,如下所示:

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)
    }
}

第二个视图控制器的ViewControllerA实例 - 名为setupViewControllerA()的方法 - 如下所示:

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()
    }
}

实现vcA.privateWork()时会出现编译时错误:

  

' privateWork'因私人'而无法访问保护水平

这是非常合适的!我想阻止vcA.privateWork()访问其他类。

我的问题是:简单地说,我想对数据源方法执行相同的操作,所以如果我尝试实现:

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

我收到编译时错误:

  

方法' tableView(_:numberOfRowsInSection:)'必须像   它的封闭类型,因为它符合协议中的要求   ' UITableViewDataSource'

提供修正建议,让private成为internal。它导致让以下代码(在第二个视图控制器中):

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

是有效的,这是不合适的,没有必要让这样的数据源方法可以从它的类外部访问。

我应该为这种情况做些什么?

2 个答案:

答案 0 :(得分:2)

您无需担心委托人的隐私权。数据源方法仍然可以选择创建另一个将处理tableview数据源内容的类

例如

class IceCreamListDataSource: NSObject, UITableViewDataSource
{
  let dataStore = IceCreamStore()

  // MARK: - Table view data source

  func numberOfSectionsInTableView(tableView: UITableView) -> Int
  {
    return 1
  }

  func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
  {
    return dataStore.allFlavors().count
  }

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
  {
    let flavor = dataStore.allFlavors()[indexPath.row]
    let cell = tableView.dequeueReusableCellWithIdentifier("IceCreamListCell", forIndexPath: indexPath)
    cell.textLabel?.text = flavor
    return cell
  }
}

现在在ViewControllerUITableViewController课程中,您可以将此课程用作数据源

class IceCreamListViewController: UITableViewController
{
  let dataSource = IceCreamListDataSource()

  // MARK: - View lifecycle

  override func viewDidLoad()
  {
    super.viewDidLoad()
    tableView.dataSource = dataSource
  }
}

希望它有用

答案 1 :(得分:1)

使表视图适配器符合UITableViewDataSourceUITableViewDelegate,并将其作为私有属性添加到视图控制器:

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
        }
    }

}