То, что вы сделали, создали два бита состояния, которые зависят друг от друга. Было бы лучше иметь только один источник правды и производную, что означает, что один должен быть реализован иначе, чем другой. Предполагая, что 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
let, а не 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
}
}
}
Идея заключается в том, что субъекты (переменная является своего рода субъектом) не должны быть первыми, о чем вы думаете, когда делаете наблюдаемое, зависящее от некоторого другого наблюдаемого. В этом отношении они хороши только для создания начальных наблюдаемых. (RxCocoa их полон.)
Да, и, кстати, Variable
устарел.