【发布时间】:2018-07-07 20:56:20
【问题描述】:
我有一个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 文档日:
如果您将闭包分配给类实例的属性,并且该闭包的主体捕获该实例,也会发生强引用循环。
这个viewController 包含一个viewController,它包含一个捕获viewController 的闭包,所以我知道可能会发生强引用循环。
这些是viewModel 的属性:
var onModelChange: (() -> Void)?
private var model: [MyModel] = [MyModel]() {
didSet {
self.onModelChange?()
}
}
另一方面,这个viewController 是root 一个,所以在应用程序的生命周期内不会被释放。而且我没有明确 nilify 它的 viewModel 属性。所以:
- 问题 1:是否真的存在发生强参考周期的风险?我是否应该向闭包提供捕获列表?
-
问题 2:我将捕获列表设置为
[weak self],但是,由于似乎viewController和它的viewModel会同时被释放,我想我应该定义[unowned self]?如果有疑问,定义[weak self]会不会很痛苦?
让我们认为现在viewController 是推到root 之上的一个,因此它可能会在应用程序的生命周期内弹出。 viewController的fetchData()方法是这样的:
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 不是viewModel 的属性,就像dataSource 一样,它是一个只提供static func 的类。那些static func 被传递为@escaping 的闭包,所以我想在这种情况下也可能发生强引用循环,对吧?还是这种情况与以前的情况不同?我在这里需要哪个捕获列表(如果有的话)?
【问题讨论】:
标签: ios swift closures weak-references retain-cycle