从RxSwift4开始,Variable移动到Deprecated.swift标记Variable未来可能的弃用.建议的替代方案Variable是BehaviorRelay.在发布这个问题时,由于我在网上找不到太多的教程,BehaviorRelay我在SO中发布了这样一个基本问题.
假设我正在进行webService调用,并且我收到一块JSONArray数据,在逐个解析JSON对象时我更新了我的Variable的value属性
这是我的变量声明
var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data: "{:}")])
Run Code Online (Sandbox Code Playgroud)
每次我将变量更新为获取新元素时
myFilter.value.append(newModel)
Run Code Online (Sandbox Code Playgroud)
当Variable绑定到CollectionView时,collectionVie将立即使用新添加的对象更新其UI.
使用BehaviorRelay的问题
现在我的声明看起来像
var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data: "{:}")])
Run Code Online (Sandbox Code Playgroud)
但最大的问题myFilter.value是readOnly.很明显
myFilter.value.append(newModel)
Run Code Online (Sandbox Code Playgroud)
不是解决方案.我发现我可以使用accept.
但是现在当我尝试解析响应中的每个元素并更新myFilter的值时
self?.expertsFilter.accept(newModel)
Run Code Online (Sandbox Code Playgroud)
上面的陈述给出了错误引用
无法将NewModel的值转换为预期的争论类型[NewModel]
显然,它期待一个数组而不是一个单独的元素.
解决方法:
解决方案1:
因此,一个解决方案是在临时数组中累积所有响应并且一旦完成触发 self?.expertsFilter.accept(temporary_array)
解决方案2:
如果我必须onNext在解析每个元素时向订阅者发送事件,我需要将self?.expertsFilter的值复制到new Array,将新解析的元素添加到它并返回新数组.
解决方案3:
摆脱BehaviorRelay并使用BehaviorSubject/PublishSubject
前两个声音令人沮丧,因为可能需要在解析每个元素时触发UI我不能等到解析整个响应.因此,解决方案1显然没有多大用处.
第二种解决方案更加可怕,因为它每次发送onNext事件时都会创建一个新数组(我知道它是临时的并且将被释放).
题:
因为BehaviorRelay被提议作为Variable进入两难的替代方案,我accept正确使用?有没有更好的方法来解决它?
请帮忙
dal*_*ook 19
您是否考虑过从继电器上的现有值创建一个新数组,追加,然后调用accept?
myFilter.accept(myFilter.value + [newModel])
Run Code Online (Sandbox Code Playgroud)
小智 10
基于道尔顿的答案,这是一个方便的扩展:
extension BehaviorRelay where Element: RangeReplaceableCollection {
func acceptAppending(_ element: Element.Element) {
accept(value + [element])
}
}
Run Code Online (Sandbox Code Playgroud)
我写了这个扩展名,用Variables 代替BehaviorRelays。您可以根据此模式添加所需的任何方法来轻松迁移。
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)
}
}
Run Code Online (Sandbox Code Playgroud)
相反Variable.value.funcName,现在您写BehaviorRelay.funcName。
使用where Element: RangeReplaceableCollection子句的想法来自retendo的答案
还要注意,indexis是类型Element.Index,不是Int或其他任何类型。
我创建了这些扩展,使用两种方法来促进迁移,以防您有数组变量并且必须使用附加。
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)
}
}
Run Code Online (Sandbox Code Playgroud)
你这样称呼它
var things = BehaviorRelay<[String]>(value: [])
things.append("aa")
let otherThings = ["bb", "cc"]
things.append(contentsOf: otherThings)
things.remove(at: 0)
things.removeAll()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18326 次 |
| 最近记录: |