繁体   English   中英

强参考周期:闭包与方法

[英]Strong reference cycle: closures vs methods

我有一个包含名为TableViewControllerUITableViewController的项目。 因为我希望我的UITableViewDataSource协议声明在我的TableViewController声明之外,所以我设置了以下代码(受Objc.io Lighter View Controllers启发):

TableViewController:

class TableViewController: UITableViewController {

    let array = [["1"], ["2", "3", "4"], ["5", "6"]]
    var dataSource: DataSource!


    override func viewDidLoad() {
        super.viewDidLoad()

        dataSource = DataSource(array: array, configureCellBlock: { (cell, item) in
            cell.textLabel.text = item
        })
        tableView.dataSource = dataSource
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    deinit {
        println("Quit TVC")
    }

}

数据源:

class DataSource: NSObject, UITableViewDataSource {

    let array: [[String]]
    typealias TableViewCellConfigureBlock = (cell: UITableViewCell, item: String) -> ()
    var configureCellBlock: TableViewCellConfigureBlock


    init(array: [[String]], configureCellBlock: TableViewCellConfigureBlock) {
        self.array = array
        self.configureCellBlock = configureCellBlock

        super.init()
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return array.count
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array[section].count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

        let data = array[indexPath.section][indexPath.row]
        configureCellBlock(cell: cell, item: data)

        return cell
    }

    deinit {
        println("Quit DataSource")
    }

}

这很好用。 但是现在,我想用一个方法替换configureCellBlock闭包。 所以我已经将我的TableViewController代码更改为:

class TableViewController: UITableViewController {

    let array = [["1"], ["2", "3", "4"], ["5", "6"]]
    var dataSource: DataSource!


    override func viewDidLoad() {
        super.viewDidLoad()

        dataSource = DataSource(array: array, configureCellBlock: formatCell)
        tableView.dataSource = dataSource
    }

    func formatCell(cell: UITableViewCell, item: String) -> () {
        cell.textLabel.text = item
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    deinit {
        println("Quit TVC")
    }

}

问题现在很明显:如果我运行此代码,由于强大的引用周期, TableViewControllerDataSource永远不会被释放。

我一直在尝试将我的dataSource声明更改为weak var dataSource: DataSource! 或者unowned var dataSource: DataSource但我最近没有尝试过。

如何用方法替换configureCellBlock闭包? 我是否必须使用协议委托模式来执行此操作? 它会是什么样子?

问题是对formatCell的引用具有对self的隐含引用。 这不是通过使数据源变弱来解决的(您肯定希望在那里使用强引用),而是确保数据源中的块变量不会将强引用保留回视图控制器。 所以,你要将[unowned self]添加到闭包的开头:

dataSource = DataSource(array: array) {
    [unowned self] cell, item in

    self.formatCell(cell, item: item)
    return
}

您可以使用如下代理实现它:

@objc protocol TableViewCellConfigurator {
  func dataSource( dataSource: DataSource, configureCell cell: UITableViewCell, item: String)
}

class DataSource: NSObject, UITableViewDataSource {
  weak var cellConfigurator: TableViewCellConfigurator?

  (...)

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    let data = array[indexPath.section][indexPath.row]
    if let delegate = cellConfigurator {
      cellConfigurator.dataSource( self, configureCell: cell, item: data)
    }
    return cell
  }

  (...)

}


class TableViewController: UITableViewController: TableViewCellConfigurator {

  override func viewDidLoad() {
    super.viewDidLoad()

    dataSource = DataSource(array: array, configureCellBlock: formatCell)
    tableView.dataSource = dataSource
    dataSource.cellConfigurator = self
  }

  override func dataSource( dataSource: DataSource, configureCell cell: UITableViewCell, item: String) {
    cell.textLabel.text = item
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM