Skip to main content
 首页 » 操作系统

ios之强引用循环 : closures vs methods

2024年01月01日41artech

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

TableView Controller :

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 永远不会因为强引用循环而被释放。

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

如何用方法替换我的 configureCellBlock 闭包?我是否必须使用协议(protocol)委托(delegate)模式才能这样做?它会是什么样子?

请您参考如下方法:

问题是对 formatCell 的引用隐含了对 self 的引用。这不是通过使数据源变弱来解决的(你肯定希望那里有一个强引用),而是确保数据源中的 block 变量不维护返回 View Controller 的强引用。因此,您可以将 [unowned self] 添加到闭包的开头:

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