【问题标题】: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: ...)

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

遇到这种情况该怎么办?

【问题讨论】:

    标签: ios swift delegates encapsulation access-modifiers


    【解决方案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...
      猜你喜欢
      • 2014-12-10
      • 1970-01-01
      • 2023-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      • 1970-01-01
      • 2019-10-30
      相关资源
      最近更新 更多