强参考周期:闭包与方法

时间:2014-10-26 13:14:28

标签: ios methods swift closures

我的项目包含名为UITableViewController的{​​{1}}。因为我希望我的TableViewController协议声明不在我的UITableViewDataSource声明之内,所以我设置了以下代码(受Objc.io Lighter View Controllers启发):

TableViewController:

TableViewController

的DataSource:

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") } } TableViewController永远不会因为强大的参考周期而被释放。

我一直在尝试将DataSource声明更改为dataSourceweak var dataSource: DataSource!,但我最近的尝试都没有奏效。

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

2 个答案:

答案 0 :(得分:2)

问题是对formatCell的引用隐含了对self的引用。这不是通过使数据源变弱来解决的(您肯定希望在那里使用强引用),而是确保数据源中的块变量不会将强引用保留回视图控制器。因此,您需要在关闭开始时添加[unowned self]

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

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

答案 1 :(得分:1)

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

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