表格视图单元格按钮关闭是否需要弱自我

问题描述

在尝试避免保留周期时,是否有必要在UITableViewCell按钮操作中使用[weak self] in?示例:

在ViewController的cellForRow

cell.buttonAction = { (cell) [weak self] in
     self.someFunction()
}

在TableViewCell类中

var buttonAction: ((UITableViewCell) -> Void)?

@IBAction func buttonPressed(_ sender: Any) {
     buttonAction?(self)
}

解决方法

要考虑的关键是:

var buttonAction: ((UITableViewCell) -> Void)?

您打算在实例属性中长期存储功能

现在考虑谁指/拥有谁。视图控制器拥有其视图,该视图或拥有拥有单元格的表视图。同时,细胞拥有功能。如果函数强烈引用我刚才提到的任何对象,则那是一个保留周期。这是一个经典保留周期,这是保留周期如何形成的绝对模型。


[我想补充一下我如何测试这些东西。有一种非常便宜和简便的方法:将视图控制器包装在导航控制器中,再加上一个空白的根视图控制器,以便可以将视图控制器推入。在您的视图控制器中实现deinit。现在运行该应用程序,推动您的视图控制器,进行一些操作,然后使用“后退”按钮将其弹出。如果未调用deinit,则您有一个保留周期。]

,

是的,在这种情况下,必须使用unownedweak来捕获self

  • 您的视图控制器很可能会强烈引用UITableView
  • 表视图对其UITableViewCells
  • 有很强的引用
  • 每个单元格都强烈引用您的buttonAction结束符。

直接使用self具有保留周期的作用。

这实际上很容易测试。尝试提供以下视图控制器并将其关闭:

class TestTableViewCell: UITableViewCell {
    var closure: (() -> Void)?
    
    deinit {
        print("TestTableViewCell deinit!")
    }
}

class TestTableViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(TestTableViewCell.self,forCellReuseIdentifier: "TestTableViewCellIdentifier")
    }
    
    deinit {
        print("TestTableViewController deinit!")
    }
    
    override func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TestTableViewCellIdentifier",for: indexPath) as! TestTableViewCell
        
        cell.closure = { [weak self] in
            guard let self = self else { return }
            self.testFunction()
        }
        
        return cell
    }
    
    func testFunction() {}
}

// Test present
let controller = TestTableViewController()
present(controller,animated: true) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        self.dismiss(animated: true)
    }
}

您将获得以下输出:

TestTableViewController deinit!
TestTableViewCell deinit!

现在呈现不带弱点的相同视图控制器,您将看到没有输出,这意味着deinit函数不会被调用,并且对象将保留在内存中。

,

如果您不使用tableviewcell的对象,而只想对单元格执行操作,请执行此操作。

var buttonAction: (() -> Void)?

@IBAction func buttonPressed(_ sender: Any) {
     buttonAction?()
}

在cellForRow上使用它,

cell.buttonAction = { [weak self] in
     self?.someFunction()
}

对于检查保留周期,我通常使用此选项检查内存是否保留。 enter image description here

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...