[英]Strong reference cycle: closures vs methods
我有一个包含名为TableViewController
的UITableViewController
的项目。 因为我希望我的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")
}
}
问题现在很明显:如果我运行此代码,由于强大的引用周期, TableViewController
和DataSource
永远不会被释放。
我一直在尝试将我的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.