How to use BehaviorRelay as an alternate to Variable in RxSwift?
从RxSwift4开始,
假设我正在进行一个webService调用,并且接收到一大堆数据,即JSONArray,则一一解析JSON对象,然后更新了Variable的value属性
这是我的变量声明
1 | var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data:"{:}")]) |
每次获取新元素时,我将我的变量更新为
1 | myFilter.value.append(newModel) |
当Variable绑定到CollectionView时,collectionVie将立即使用新添加的对象更新其UI。
BehaviorRelay问题
现在我的声明看起来像
1 | var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data:"{:}")]) |
但是最大的问题是
1 | myFilter.value.append(newModel) |
不是解决方案。我发现我可以使用
但是现在当我尝试解析每个元素作为响应并更新myFilter的值时
1 | self?.expertsFilter.accept(newModel) |
上面的语句给出了错误引用
Can not convert the value of NewModel to expected arguement type
[NewModel]
显然,它期望数组而不是单个元素。
解决方法:
解决方案1:
因此,一种解决方案是将所有响应累积在一个临时数组中,一旦完成触发
解决方案2:
如果在解析每个元素时必须向订阅者发送
解决方案3:
摆脱
前两个声音令人沮丧,因为解析每个元素时可能需要触发UI,我迫不及待要解析整个响应。因此很明显,solution1并没有太多用处。
第二种解决方案更可怕,因为它每次发送onNext事件时都会创建一个新数组(我知道它是临时的,将被释放)。
题:
因为在困境中提出了
请帮忙
您是否考虑过简单地从中继上的现有值创建一个新数组,然后追加并调用
1 | myFilter.accept(myFilter.value + [newModel]) |
我写了这个扩展,用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public extension BehaviorRelay where Element: RangeReplaceableCollection { public func insert(_ subElement: Element.Element, at index: Element.Index) { var newValue = value newValue.insert(subElement, at: index) accept(newValue) } public func insert(contentsOf newSubelements: Element, at index: Element.Index) { var newValue = value newValue.insert(contentsOf: newSubelements, at: index) accept(newValue) } public func remove(at index: Element.Index) { var newValue = value newValue.remove(at: index) accept(newValue) } } |
现在,您写的是
使用
另请注意,
以道尔顿的答案为基础,这是一个方便的扩展:
1 2 3 4 5 | extension BehaviorRelay where Element: RangeReplaceableCollection { func acceptAppending(_ element: Element.Element) { accept(value + [element]) } } |
我会做这样的事情-
1 2 3 4 5 6 7 8 9 10 11 | let requests = PublishSubject<Observable<ServerResponse>>.create() let responses: Observable<ServerResponse> = requests.switchLatest() let parsed: Observable<[ParsedItem]> = responses .flatMap { Observable.from($0).map { parse($0) }.toArray() } parsed.bind(to: ui) // repeated part let request1: Observable<ServerResponse> = servive.call() request.onNext(request1) |
我创建了这些扩展,使用了两种方法来方便迁移,以防万一您拥有数组变量并且必须使用append。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | extension BehaviorRelay where Element: RangeReplaceableCollection { func append(_ subElement: Element.Element) { var newValue = value newValue.append(subElement) accept(newValue) } func append(contentsOf: [Element.Element]) { var newValue = value newValue.append(contentsOf: contentsOf) accept(newValue) } public func remove(at index: Element.Index) { var newValue = value newValue.remove(at: index) accept(newValue) } public func removeAll() { var newValue = value newValue.removeAll() accept(newValue) } } |
你这样称呼它
1 2 3 4 5 6 | var things = BehaviorRelay<[String]>(value: []) things.append("aa") let otherThings = ["bb","cc"] things.append(contentsOf: otherThings) things.remove(at: 0) things.removeAll() |
AshKan的答案很好,但我来这里是为了寻找解决方案中缺少的方法。
附加:
1 2 3 4 5 6 7 8 9 | extension BehaviorRelay where Element: RangeReplaceableCollection { func append(_ subElement: Element.Element) { var newValue = value newValue.append(subElement) accept(newValue) } } |