3

我试图将我的 tableView 的数据源分离到一个单独的委托对象中。由于该委托需要在某些时候访问 tableview,因此我需要对委托中的委托对象的引用;并且由于两者都是类,因此我需要通过委托来避免强引用循环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 会抛出一个警告:“实例将立即被释放,因为属性‘tableViewDelegate’是‘弱’”

所以要修复它,我执行以下操作:

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() 方法中初始化委托,我没有创建强引用的危险,因为一旦我们离开该方法的范围,保存该实例的变量就会被释放。或者换一种说法:我们唯一需要担心一个变量(指向一个类)创建一个强引用是变量是否在类级别初始化,因此只要类存在.

那是对的吗?

4

2 回答 2

3

请确认以下是否正确:通过在 viewDidLoad() 方法中初始化委托,我没有创建强引用的危险,因为一旦我们离开该方法的范围,保存该实例的变量就会被释放。

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

不幸的是,这意味着您的委托仍将被解除分配。您所做的只是使警告静音。

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


回复以下评论:

我发现的几乎所有教程的委托属性都很弱,所以这似乎是标准做法。

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

如果您考虑一下,您TableViewDelegate正在被用来代替MyViewController遵守协议。拥有代表是绝对有道理的MyViewController

于 2019-03-02T09:24:27.947 回答
0

这就是我解决这个问题的方法:

    let dataSource = MyDataSource()

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

然后在 viewDidLoad() 中:

    tableView.delegate = self
    tableView.dataSource = dataSource

您可以在此处查看完整的演示项目

于 2019-10-14T14:22:59.950 回答