UITableViewDiffableDataSource 不是 deinit

Posted

技术标签:

【中文标题】UITableViewDiffableDataSource 不是 deinit【英文标题】:UITableViewDiffableDataSource are not deinit 【发布时间】:2022-01-21 14:39:46 【问题描述】:

我想在我的项目中使用组合并面对问题。 这是 ViewController 的代码

import Combine
import UIKit

class ProfileDetailsController: ViewController 
    //

    // MARK: - Views
    @IBOutlet private var tableView: UITableView!

    // MARK: - Properties
    private typealias DataSource = UITableViewDiffableDataSource<ProfileDetailsSection, ProfileDetailsRow>
    private typealias Snapshot = NSDiffableDataSourceSnapshot<ProfileDetailsSection, ProfileDetailsRow>

    @Published private var data: [ProfileDetailsSectionModel] = 
        return ProfileDetailsSection.allCases.map  ProfileDetailsSectionModel(section: $0, data: $0.rows) 
    ()
    
    private lazy var dataSource: DataSource = 
        let dataSource = DataSource(tableView: tableView)  tableView, _, model in
            let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldTableCell.name) as! TextFieldTableCell
            cell.delegate = self
            cell.setData(model: model)
            return cell
        
        dataSource.defaultRowAnimation = .fade
        return dataSource
    ()


// MARK: - Setup binding
extension ProfileDetailsController 
    override func setupBinding() 
        tableView.registerCellXib(cell: TextFieldTableCell.self)
        $data.receive(on: RunLoop.main).sink  [weak self] models in
            let sections = models.map  $0.section 
            var snapshot = Snapshot()
            snapshot.appendSections(sections)
            models.forEach  snapshot.appendItems($0.data, toSection: $0.section) 
            self?.dataSource.apply(snapshot, animatingDifferences: true)
        .store(in: &cancellable)
    


// MARK: - Cell delegates
extension ProfileDetailsController: TextFieldTableCellDelegate 
    func switcherAction()  

这是单元格的代码。

import UIKit

protocol TextFieldTableCellData 
    var placeholder: String?  get 


protocol TextFieldTableCellDelegate: NSObjectProtocol 
    func switcherAction()


class TextFieldTableCell: TableViewCell 
    //

    // MARK: - Views
    @IBOutlet private var textField: ZWTextField!

    // MARK: - Properties
    public weak var delegate: TextFieldTableCellDelegate?

    override class var height: CGFloat 
        return 72
    


// MARK: - Public method
extension TextFieldTableCell 
    func setData(model: TextFieldTableCellData) 
        textField.placeholder = model.placeholder
    

ViewController 的deinit 未被调用。 但是当我将此代码用于 ViewController 时

import UIKit

class ProfileDetailsController: ViewController 
    //

    // MARK: - Views
    @IBOutlet private var tableView: UITableView!

    // MARK: - Properties
    @Published private var data: [ProfileDetailsSectionModel] = 
        return ProfileDetailsSection.allCases.map  ProfileDetailsSectionModel(section: $0, data: $0.rows) 
    ()


// MARK: - Startup
extension ProfileDetailsController 
    override func startup() 
        tableView.dataSource = self
        tableView.registerCellXib(cell: TextFieldTableCell.self)
    


// MARK: - Startup
extension ProfileDetailsController: UITableViewDataSource 
    func numberOfSections(in tableView: UITableView) -> Int 
        return data.count
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return data[section].data.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let model = data[indexPath.section].data[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldTableCell.name) as! TextFieldTableCell
        cell.delegate = self
        cell.setData(model: model)
        return cell
    


// MARK: - Cell delegates
extension ProfileDetailsController: TextFieldTableCellDelegate 
    func switcherAction() 

一切都很好。 deinit 打来电话。我尝试将 dataSource 设置为可选并将其设置为零 deinit,结果相同。只有当我评论这一行时才会调用组合 deinit:

cell.delegate = self

有谁知道怎么回事? Xcode 13.2 ios 15.2

【问题讨论】:

这不是答案,但请注意您的代码是错误的。您不应该制作新的快照;您应该获取并修改现有数据的快照。 另外protocol TextFieldTableCellDelegate: NSObjectProtocol 是错误的。这应该是 AnyObject。同样,这不是答案,只是观察。 【参考方案1】:

Combine 的东西完全是红鲱鱼。这就是你找不到问题的原因;你找错地方了。问题在于老式数据源和可区分数据源之间的区别。问题出在这里:

private lazy var dataSource: DataSource =  // *
    let dataSource = DataSource(tableView: tableView)  tableView, _, model in
        let cell = tableView.dequeueReusableCell(withIdentifier: TextFieldTableCell.name) as! TextFieldTableCell
        cell.delegate = self // *

我已为有问题的行加注星标:

一方面,您(self,视图控制器)保留了dataSource

另一方面,您为数据源提供了一个单元格提供程序函数,您在其中提到了self

这是一个保留循环!你需要打破这个循环。改变

let dataSource = DataSource(tableView: tableView)  tableView, _, model in

let dataSource = DataSource(tableView: tableView)  [weak self] tableView, _, model in

(这将编译,因为虽然self 现在是可选的,但cell.delegate 也是。)

【讨论】:

以上是关于UITableViewDiffableDataSource 不是 deinit的主要内容,如果未能解决你的问题,请参考以下文章