如何在 RxSwift 中使可变字典可见
How can a mutable dictionary be made observable in RxSwift
我们希望使用可观察的字典来通知任何订阅者发生变化。到目前为止,这是作为 BehaviorRelay<[KeyType: ValueObjectType]>
实现的
现在我们需要 add/remove/change observable 中字典的值。我们尝试了以下方法(简单来说),但没有用:
let list = BehaviorRelay<[String: MyClassType]>.init([:])
let newElem = MyClassType()
list.value.updateValue(newElem, forKey: "anykey")
编译器抱怨:不能在不可变值上使用可变成员:'value' 是只获取 属性
下面的方法有效,但我发现它很麻烦,而且性能方面可能效率低下:
let list = BehaviorRelay<[String: MyClassType]>.init([:])
let newElem = MyClassType()
let newList = list.value
newList.updateValue(newElem, forKey: "anykey")
list.accept(newList)
UI 侧列表的典型订阅者是例如UITableView 或 UICollectionView。
有没有更好的方法来处理这个问题?
你的第二条路是要走的路。可以通过这样写来改进繁琐明智的:
let list = BehaviorRelay<[String: MyClassType]>.init(value: [:])
list.accept(list.value.merging(["anykey": MyClassType()]){ (_, new) in new })
如果必须多次执行此操作,以下扩展可以派上用场
extension Dictionary where Key == String, Value == MyClassType {
static func + (lhs: [String : MyClassType], rhs: [String : MyClassType]) -> [String : MyClassType] {
return lhs.merging(rhs) { (_, new) in new }
}
}
现在你可以这样做了list.accept(list.value + ["anykey": MyClassType()])
请注意,如果右侧操作数的键也存在于左侧操作数中,则右侧值将覆盖左侧值。据我了解,这是您想要的行为。
您尝试的第一种方法也适用于 Variable
。但是 Variable
现在被认为已弃用,取而代之的是 BehaviorRelay
和 value
属性 of BehaviourRelay
is only get.
在评论中与@JR 讨论后,可以为 BehaviorRelay
编写通用扩展,其中 Element
是 Array
/ Dictionary
extension BehaviorRelay {
func addElement<T>(element: T) where Element == [T] {
accept(value + [element])
}
func removeElement<T>(element: T) where Element == [T], T: Equatable {
accept(value.filter {[=12=] != element})
}
func addElement<T, U>(key: T, value: U) where Element == [T: U] {
accept(self.value.merging([key: value]) { (_, new) in new })
}
func removeElemnent<T>(key: T) where Element == [T: Any] {
accept(self.value.filter {dictElemnt in dictElemnt.key != key})
}
}
我们希望使用可观察的字典来通知任何订阅者发生变化。到目前为止,这是作为 BehaviorRelay<[KeyType: ValueObjectType]>
实现的现在我们需要 add/remove/change observable 中字典的值。我们尝试了以下方法(简单来说),但没有用:
let list = BehaviorRelay<[String: MyClassType]>.init([:])
let newElem = MyClassType()
list.value.updateValue(newElem, forKey: "anykey")
编译器抱怨:不能在不可变值上使用可变成员:'value' 是只获取 属性
下面的方法有效,但我发现它很麻烦,而且性能方面可能效率低下:
let list = BehaviorRelay<[String: MyClassType]>.init([:])
let newElem = MyClassType()
let newList = list.value
newList.updateValue(newElem, forKey: "anykey")
list.accept(newList)
UI 侧列表的典型订阅者是例如UITableView 或 UICollectionView。
有没有更好的方法来处理这个问题?
你的第二条路是要走的路。可以通过这样写来改进繁琐明智的:
let list = BehaviorRelay<[String: MyClassType]>.init(value: [:])
list.accept(list.value.merging(["anykey": MyClassType()]){ (_, new) in new })
如果必须多次执行此操作,以下扩展可以派上用场
extension Dictionary where Key == String, Value == MyClassType {
static func + (lhs: [String : MyClassType], rhs: [String : MyClassType]) -> [String : MyClassType] {
return lhs.merging(rhs) { (_, new) in new }
}
}
现在你可以这样做了list.accept(list.value + ["anykey": MyClassType()])
请注意,如果右侧操作数的键也存在于左侧操作数中,则右侧值将覆盖左侧值。据我了解,这是您想要的行为。
您尝试的第一种方法也适用于 Variable
。但是 Variable
现在被认为已弃用,取而代之的是 BehaviorRelay
和 value
属性 of BehaviourRelay
is only get.
在评论中与@JR 讨论后,可以为 BehaviorRelay
编写通用扩展,其中 Element
是 Array
/ Dictionary
extension BehaviorRelay {
func addElement<T>(element: T) where Element == [T] {
accept(value + [element])
}
func removeElement<T>(element: T) where Element == [T], T: Equatable {
accept(value.filter {[=12=] != element})
}
func addElement<T, U>(key: T, value: U) where Element == [T: U] {
accept(self.value.merging([key: value]) { (_, new) in new })
}
func removeElemnent<T>(key: T) where Element == [T: Any] {
accept(self.value.filter {dictElemnt in dictElemnt.key != key})
}
}