这是我们用例的一个示例:
我们有一个selectedIndex
和一个items
的列表。
class FoosViewModel {
let selectedIndex = Variable<Int>(0)
let items: [Foo] = ... // assume that this is initialized properly
}
实际上,我们经常关心选择哪个项目而不是所选项目的索引。因此,我们将获得如下代码:
selectedIndex.asObservable().subscribe(onNext: { [weak self] index in
guard let self = self else { return }
let selectedItem = items[index]
// Do sth with `selectedItem` here
}
请注意,selectedItem
的值始终由selectedIndex
驱动。因此,我们将代码更改为以下内容:
class FoosViewModel {
let selectedIndex = Variable<Int>(0)
let selectedItem = Variable<Int>(items[0])
let items: [Foo] = ... // assume that this is initialized properly
init() {
selectedIndex.asObservable().subscribe(onNext: { [weak self] index in
guard let self = self else { return }
self.selectedItem = items[index]
}
}
}
这似乎是一个足够普遍的用例。我们在Rx中是否已有可以将Variable
映射到另一个的运算符?有这样的东西吗?
class FoosViewModel {
let selectedIndex = Variable<Int>(0)
let selectedItem = selectedIndex.map{ items[$0] }
let items: [Foo] = ... // assume that this is initialized properly
}
答案 0 :(得分:1)
您所做的是创建两个相互依赖的状态位。最好有一个真理的来源和一个派生,这意味着一个应该与另一个不同地实现。假设selectedIndex
是真理的源头,那么我希望看到:
class FoosViewModel {
let selectedIndex = Variable<Int>(0)
let selectedItem: Observable<Foo?>
let items: [Foo]
init(items: [Foo]) {
selectedItem = selectedIndex.asObservable().map { index in
index < items.count ? items[$0] : nil
}
self.items = items
}
}
与您的尝试不同,此类的用户没有诱惑力尝试为selectedItem
分配新值(实际上,如果尝试,该代码甚至都不会编译。)有益的是,由于地图完全没有引用self
,因此也无需进行“弱自舞”。所有这一切都是因为您让items
而不是让var(对您有好处!)
如果您希望能够添加/删除项目,那么事情会变得更加复杂...
class MutableFooViewModel {
let selectedIndex = Variable<Int>(0)
let selectedItem: Observable<Foo?>
let items = Variable<[Foo]>([])
init(items: [Foo]) {
items.value = items
let _items = self.items // this is done to avoid reference to `self` in the below.
selectedItem = Observable.combineLatest(
_items.asObservable(),
selectedIndex.asObservable()
) { items, index in
index < items.count ? items[index] : nil
}
}
}
这里的想法是,在创建依赖于其他可观察对象的Observable时,您首先想到的不是Subject(变量是一种主题)。在这方面,它们仅适用于创建初始可观察值。 (RxCocoa装满了它们。)
哦,顺便提一下,Variable
已过时。