我一直在寻找一种在更新变量时自动更新UI的简便方法。常规KVO是如此混乱的代码,所以我一直在看RxSwift,ReactiveCocoa等,但发现这些很难掌握,还有很多新对象和太多我不需要的东西。
我一直在玩变量的didSet
,以及我的对象中的一个emtpy可选功能。希望展示比解释更容易:
自定义对象(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?()
}
}
我们假设AwesomeView
中存在此自定义视图UIViewController
作为出口。
我创建了AwesomeViewModel
的实例,然后调用self.awesomeView.bindViewModel(awesomeViewModel)
。
当我稍后,在我的UIViewController
(或其他任何地方,可以传递它)执行类似awesomeViewModel.awesomeText = "Hello World"
之类的操作时,那么viewModel的变量didSet将触发可选函数{{ 1}}。由于此功能已由自定义视图updateBlock
设置,因此它将自动更新该视图中标签中的文本。
我认为这很酷,而且很容易理解,但这有什么副作用,或者我没有看到的东西?这是不好的做法吗?它似乎比使用标准KVO与所有功能和观察等更容易。
我正在考虑将此用于AwesomeView
,UITableViewCell
将在bindViewModel()
中调用cellForRowAtIndexPath
。我不认为有任何保留周期或任何东西,但我不太擅长发现它们。
我希望在将这个方法应用到我的应用程序之前获得一些关于此方法的优点和缺点 - 只是为了找出它是世界上最愚蠢的想法。但对我来说似乎没问题。
答案 0 :(得分:2)
我相信学习RxSwift是个好主意。但与此同时,你所做的一切都很好。这种方法的局限性在于您只能进行一次回调; RxSwift允许对一个Observable进行任意数量的订阅。我提前道歉,这个答案是基于意见的。
我会将updateBlock
更改为具有“观察”值作为参数,即
var updateBlock: ((String) -> ())?
因为这可以帮助避免保留周期,并且可能重命名updateBlock
以更准确地反映哪个值已经改变,即
var awesomeTextUpdate: ((String) -> ())?
但是,@ marddy是对的,这可能会让您感到痛苦,您可能希望观察多个属性。这可以通过一系列属性及其值来部分地解决,例如,
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可能是更好的长期解决方案。但是,如果你不能广泛地复制这个范例,可选功能就可以了。记住:不要重复自己。
你正在做的事看起来很合理,但不能很好地扩展。