我一直在寻找一种在更新变量时自动更新 UI 的简便方法。常规 KVO 的代码非常困惑,所以我一直在研究 RxSwift、ReactiveCocoa 等,但发现这些很难掌握,还有很多新对象和太多我不需要的东西。
我一直在研究变量的 didSet
,以及我对象中的空可选函数。希望展示比解释更容易:
自定义对象(viewModel)
class AwesomeViewModel{
var awesomeText:String { didSet { updateBlock?() } }
var updateBlock:(()->())?
init(awesomeText:String){
self.awesomeText = awesomeText
}
}
还有一个自定义的 UIView:
class AwesomeView:UIView{
@IBOutlet weak var awesomeLabel: UILabel!
func bindViewModel(viewModel:AwesomeViewModel){
viewModel.updateBlock = { [weak self] in
self?.awesomeLabel.text = viewModel.awesomeText
}
viewModel.updateBlock?()
}
}
假设此自定义 View AwesomeView
作为导出存在于 UIViewController
中。
我创建了一个 AwesomeViewModel
实例,然后调用 self.awesomeView.bindViewModel(awesomeViewModel)
。
稍后,当我在我的 UIViewController
(或其他任何地方,就此而言,它可以传递)中执行类似 awesomeViewModel.awesomeText = "Hello World"
的操作,然后viewModel的变量的didSet会触发可选函数updateBlock
。由于此功能已由自定义 View AwesomeView
设置,因此它将自动更新该 View 中标签中的文本。
我觉得这很酷,也很容易理解,但是这有什么副作用吗,或者我没有看到的东西?这是不好的做法吗?它似乎比使用具有所有功能和观察等的标准 KVO 容易得多。
我正在考虑将它用于 UITableViewCell
,其中 bindViewModel()
将在 cellForRowAtIndexPath
中调用。我不认为有任何保留周期或任何东西,但我不太擅长发现它们..
在将此方法应用到我的应用程序之前,我希望了解一些关于此方法的优缺点 - 结果发现这是世界上最愚蠢的想法。但对我来说似乎没问题。
最佳答案
我相信学习 RxSwift 是个好主意。但是与此同时,您所做的大部分都很好。这种方法的局限性在于您只能使用一个回调; RxSwift 将允许任意数量的订阅一个 Observable。我提前道歉,这个答案是完全基于意见的。
我会更改 updateBlock
以将“观察到的”值作为参数,即
var updateBlock: ((String) -> ())?
因为这有助于避免循环保留,并且可能重命名 updateBlock
以更准确地反射(reflect)哪个值发生了变化,即
var awesomeTextUpdate: ((String) -> ())?
但是,@rmaddy 是对的,这会成为您可能希望观察到的多个属性的痛苦。这可以通过属性及其值的枚举来部分解决,例如
class AwesomeViewModel {
enum Property {
case awesomeText(String)
case awesomeNumber(Int)
}
}
并更改 updateBlock
以具有类型
var updateBlock: ((AwesomeViewModel.Property) -> ())?
和 didSet
到
var awesomeText: String {
didSet {
updateBlock?(.awesomeText(awesomeText))
}
}
然后客户端可以简单地switch
Property
枚举;在他们不关心的地方中断并访问他们关心的地方。如果您有许多潜在可观察的属性,但客户在特定情况下只需要一个,这可能会很痛苦。
如果看起来没有正确的妥协,那主要是因为没有,而 RxSwift 可能是更好的长期解决方案。但是,如果您不想广泛复制此范例,那么可选函数就可以了。记住:不要重复自己。
tl;dr 你所做的看起来很合理,但扩展性不佳。
关于ios - 在变量的 didSet 中调用可选函数是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41601757/