gpt4 book ai didi

ios - MVVM - 使用闭包将 ViewModel 与数据源绑定(bind) : capture list needed?

转载 作者:行者123 更新时间:2023-11-28 07:45:14 25 4
gpt4 key购买 nike

我有一个 viewController 保持对其 viewModel 的(强)引用

lazy private var viewModel: ListViewModel = {
return ListViewModel()
}()

override func viewDidLoad() {
super.viewDidLoad()

initViewModel()
}

private func initViewModel() {
viewModel.onModelChange = { [weak self] () in
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}

viewModel.fetchData()
}

Apple 的 Swift 文档日:

A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance.

这个 viewController 包含一个 viewController,它包含一个捕获 viewController 的闭包,所以我知道可能会发生强引用循环。

这些是 viewModel 的属性:

var onModelChange: (() -> Void)?

private var model: [MyModel] = [MyModel]() {
didSet {
self.onModelChange?()
}
}

另一方面,这个 viewControllerroot 一个,所以在应用程序的生命周期中不会被释放。而且我没有明确nilify它的 viewModel 属性。所以:

  • 问题 1:实际上是否存在强引用循环发生的风险?我是否应该向闭包提供捕获列表?
  • 问题 2:我将捕获列表设置为 [weak self] 但是,因为看起来 viewController 及其 viewModel 会同时被释放,我想我应该定义 [unowned self] 来代替?在有疑问的情况下定义 [weak self] 是否有害?

假设现在 viewController 被推到 root 之上,因此它可以在应用程序的生命周期中弹出。 viewControllerfetchData() 方法是这样的:

func fetchData() {
dataSource.getData(completion: { (result, error) -> Void in
if error != nil {
self.model = [MyModel]()
} else {
if let result = result {
self.model = result
} else {
self.model = [MyModel]()
}
}
})
}

其中 dataSource 是一个强大的属性,可以从本地文件(同步任务)或调用服务(异步任务)获取数据。

model 也是一个被观察并调用 viewController 提供的闭包的属性

所以:

  • 问题 3:如果 dataSource 从本地文件获取数据。如果同时弹出 viewController 会发生什么?在 dataSource 完成之前,viewModel 是否仍然存在?在这种情况下,在闭包中提供 [weak self] 捕获列表是否正确?
  • 问题 4:如果 dataSource 正在执行异步网络调用,而 viewController 同时弹出,将是和以前一样的场景?我的意思是,在 dataSource 完成之前,viewModel 是否仍然存在?

编辑: 场景/问题 5

现在我的 viewModel 还请求一个对象 UserSettingsManager 来获取一些其他数据:

func getUserSettings() {
UserSettingsManager.getInfo { (result, error) in
if error == nil {
self.userData = result
}
}
}
}

但是这个 UserSettingsManager 不像 dataSource 那样是 viewModel 的属性,它是一个只提供 static func 的类。那些 static func 作为 @escaping 传递闭包,所以我猜在这种情况下也可能发生强引用循环,对吗?或者这种情况会不同于以前的情况吗?我在这里需要哪个捕获列表(如果有)?

最佳答案

Question 1: is there actually a risk of a strong reference cycle happening? Should I provide a capture list to the closure anyway?

强引用循环将会发生。问题应该是强引用周期是否重要。在这种情况下可能不会,但无论如何保留弱引用可能是个好主意,以防您将来移动 Controller 。为 future 的安全付出的代价很小。

Question 2: I set the capture list to be [weak self] but, since it seems the viewController and its viewModel would be deallocated same time, I guess I should have defined [unowned self] instead? Does it hurt to define [weak self] in case of doubt?

[unowned self] 表示调用闭包时 self 肯定存在。除非您完全确定是这种情况,否则您应该坚持使用 [weak self]。我的偏好是始终使用 weak,因为安全解包不需要太多额外的努力,并且如果您以某种方式错过了可以释放 self 的情况,则可以避免崩溃。如果您在闭包中多次使用 self,最好将它解包在一个 guard 语句中或将代码移动到一个单独的函数中。

Question 3: in case the dataSource is getting the data from a local file. What happens then if the viewController is pop in the meanwhile? Would the viewModel still be alive until the dataSource finishes? In such case, is it correct to provide the [weak self] capture list in the closure?

在您的示例中,您在闭包中有一个对 self 的强引用,因此您有一个强引用循环,这意味着 ViewController 永远不会被释放。

无论哪种方式,如果您同步获取数据,点击以关闭 View Controller 将无法完成它的工作,直到从文件中获取数据和 block 中的代码完成。这些必须在主线程变得畅通之前完成,并且可以执行关闭 Controller 的代码。

Question 4: in case the dataSource is performing an async network call, and the viewController is pop in the meanwhile, would be the same scenario than before? I mean, would the viewModel be still alive until the dataSource finishes?

如果您将它设为弱引用,并且 dataSource 保留在 Controller 外部,因此它比 Controller 长寿,则在调用闭包时 self 可能为 nil。

关于ios - MVVM - 使用闭包将 ViewModel 与数据源绑定(bind) : capture list needed?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51226881/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com