【问题标题】:How can a mutable dictionary be made observable in RxSwift如何在 RxSwift 中使可变字典可观察
【发布时间】:2019-08-07 08:55:12
【问题描述】:

我们希望使用可观察的字典来通知任何订阅者发生更改。到目前为止,这是作为 BehaviorRelay

实现的

现在我们需要在 observable 中添加/删除/更改字典的值。我们尝试了以下方法(简而言之),但没有奏效:

let list = BehaviorRelay<[String: MyClassType]>.init([:])
let newElem = MyClassType()
list.value.updateValue(newElem, forKey: "anykey")

编译器抱怨:不能在不可变值上使用变异成员:'value' 是一个 get-only 属性

以下方法可行,但我发现它很麻烦,而且性能方面可能效率低下:

let list = BehaviorRelay<[String: MyClassType]>.init([:])
let newElem = MyClassType()
let newList = list.value
newList.updateValue(newElem, forKey: "anykey")
list.accept(newList)

UI 端列表的典型订阅者例如是一个 UITableView 或 UICollectionView。

有没有更好的方法来处理这个问题?

【问题讨论】:

    标签: arrays swift dictionary observable rx-swift


    【解决方案1】:

    你的第二条路就是要走的路。可以通过这样写来改进繁琐

    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 现在被认为已弃用,取而代之的是BehaviorRelayBehaviourRelayvalue 属性只能获取。

    在与 cmets 中的@JR 讨论后,可以为BehaviorRelay 编写通用扩展,其中ElementArray/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 {$0 != 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})
        }
    }
    

    【讨论】:

    • 谢谢,Dictionary 扩展非常具体。也许使用仅适用于字典/数组的 acceptElement / removeElement 方法扩展 BehaviorRelay 是更好的方法?
    • 我做了 + 运算符重载,因为我通常处理可以使用加号运算符直接追加的数组。但是,是的,你是正确的 acceptElement / removeElement 扩展方法会更适合这个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 2018-06-03
    • 2018-09-07
    相关资源
    最近更新 更多