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

Posted

技术标签:

【中文标题】如何防止访问其他类的委托方法?【英文标题】:How to prevent accessing delegate methods for other classes? 【发布时间】:2018-07-23 14:18:24 【问题描述】:

为了制作“更多encapsulated”应用程序,我正在尝试为我的视图控制器属性/方法指定访问级别。但问题是当尝试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: ...)

为了有效,这是不恰当的,没有必要让这样的数据源方法可以从其类外部访问。

遇到这种情况该怎么办?

【问题讨论】:

【参考方案1】:

您无需担心委托和数据源方法的隐私,您仍然可以选择创建另一个将处理您的 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
  

希望对你有帮助

【讨论】:

【参考方案2】:

制作符合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
        
    


【讨论】:

忘记了适配器...另外,如果不需要从文件中使用,您可以将TableViewAdapter 声明为fileprivate...

以上是关于如何防止访问其他类的委托方法?的主要内容,如果未能解决你的问题,请参考以下文章

用于限制对类的访问的接口的角色

在MFC中,一个类如何调用其他类的变量和函数??

如何防止其他人在堆栈上创建您的类的新实例?

如何防止从特定类调用公共方法

我可以防止私有变量被同一类的其他对象更改吗?

类库和委托以及万能变量