如何在不触发的情况下实例化弱委托 "Instance will be immediately deallocated because property 'tableViewDelegate' is 'weak'"

How to instantiate a weak delegate without triggering "Instance will be immediately deallocated because property 'tableViewDelegate' is 'weak'"

我正在尝试将 tableView 的数据源分离到一个单独的委托对象中。由于该委托需要在某个时候访问表视图,因此我需要引用委托中的委托对象;并且由于两者都是 classes 我需要通过使委托 weak

来避免强引用循环

为此,我尝试了以下代码。

class MyViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    weak var tableViewDelegate: UITableViewDataSource?

    override func viewDidLoad() {
        super.viewDidLoad()
        tableViewDelegate = TableViewDelegate() // throwing a warning
        tableView.dataSource = tableViewDelegate
    }
}

当我尝试实例化委托时 Xcode 抛出警告:"Instance will be immediately deallocated because property 'tableViewDelegate' is 'weak'"

因此,为了修复它,我执行以下操作:

class MyViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    weak var tableViewDelegate: UITableViewDataSource?

    override func viewDidLoad() {
        super.viewDidLoad()
        let delegate = TableViewDelegate() // worried this creates a strong reference.
        self.tableViewDelegate = delegate
        tableView.dataSource = delegate
    }
}

请确认以下内容是否正确:通过在 viewDidLoad() 方法中初始化委托,我没有创建强引用的危险,因为保存该实例的变量在我们离开该方法的范围。或者换句话说:我们唯一需要担心变量(指向 class)创建强引用的情况是变量是否在 class 级别初始化,因此将和 class 一样长寿。

对吗?

Please confirm if the following is true or not: by initialising the delegate in the viewDidLoad() method I am not in danger of creating a strong reference because the variable that holds that instance is deallocated as soon as we leave the scope of that method.

正确。一旦声明 let 的范围退出,强引用就会消失。

不幸的是,这意味着您的委托仍将被释放。您所做的只是让警告静音。

基本上,您需要在某处某处具有对委托的强引用,否则它会立即消失。我的感觉是您应该使 MyViewController 中的参考变得强大。只要您的委托不包含对视图控制器的强引用,就不会有强引用循环。如果您需要在委托中引用 MyViewController,请将其设为弱引用,即视图控制器拥有委托,而不是委托拥有视图控制器。


回复以下评论:

almost all the tutorials I have found have the delegate property as weak, so it seems standard practice.

是的,这是公平的标准做法,Cocoa中也有例外。但是,标准做法是在委托对象 中弱引用委托。在您的情况下,委托对象是 UITableView 而不是 MyViewController。在您来自 Internet 的第一个示例中,FileImporter 类似于代码中的 UITableView。在第二个示例中,DetailViewController 是委托对象。

如果你仔细想想,你的 TableViewDelegate 被用来代替 MyViewController 遵守协议。 MyViewController 拥有委托人是绝对有道理的。

我是这样解决这个问题的:

    let dataSource = MyDataSource()

    lazy var viewModel : MyViewModel = {
        let viewModel = MyViewModel(dataSource: dataSource)
        return viewModel
    }()

然后在 viewDidLoad():

    tableView.delegate = self
    tableView.dataSource = dataSource

您可以看到完整的演示项目here