Ответ 1
Рассматривали ли вы просто создание нового массива из существующего значения на реле, добавление, а затем вызов accept
?
myFilter.accept(myFilter.value + [newModel])
По RxSwift4, Variable
перемещается в Deprecated.swift
маркировки возможного Deprecation из Variable
в будущем. Альтернативой, предлагаемой Variable
является BehaviorRelay
. Во время публикации этого вопроса, поскольку я не мог найти большую часть учебника по сети, используя BehaviorRelay
я размещаю такой фундаментальный вопрос здесь, в SO.
Предположим, что у меня есть вызов webService, и я получаю кусок данных, который является JSONArray, при разборе JSON-объекта один за другим. Я обновляю свойство Variable value
Вот мое объявление переменной
var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data: "{:}")])
при получении нового элемента каждый раз, когда я обновляю переменную как
myFilter.value.append(newModel)
Поскольку переменная была привязана к CollectionView, collectionVie немедленно обновлял свой интерфейс с недавно добавленным объектом.
Проблема с BehaviorRelay
Теперь моя декларация выглядит
var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data: "{:}")])
Но самая большая проблема заключается в том, что myFilter.value
является readOnly. Так очевидно
myFilter.value.append(newModel)
не является решением. Я понял, что могу использовать скорее accept
.
Но теперь, когда я пытаюсь проанализировать каждый элемент в ответ и обновить значение myFilter
self?.expertsFilter.accept(newModel)
Вышеприведенный оператор дает котировку ошибок
Невозможно преобразовать значение NewModel в ожидаемый тип аргумента [NewModel]
Очевидно, что он ожидает массив, а не отдельный элемент.
Временное решение:
Решение 1:
Таким образом, одно решение накапливает весь ответ во временном массиве и однажды запускает self?.expertsFilter.accept(temporary_array)
Решение 2:
Если мне нужно отправить событие onNext
подписчику на разбор каждого элемента, мне нужно скопировать значение self?.ExpertsFilter в новый массив, добавить к нему вновь обработанный элемент и вернуть новый массив.
Решение 3:
Избавьтесь от BehaviorRelay
и используйте BehaviorSubject
/PublishSubject
Первые два звучат угнетающе, потому что может возникнуть необходимость запуска пользовательского интерфейса при разборе каждого элемента, который я не могу подождать, пока не будет проанализирован весь ответ. Поэтому очевидно, что решение1 не очень полезно.
Второе решение гораздо более ужасно, потому что он создает новый массив (я знаю его временный и будет выпущен) каждый раз, чтобы отправить событие onNext.
Вопрос:
Поскольку BehaviorRelay
предлагается в качестве альтернативы Variable
am в дилемме, я использую accept
правильно?? Есть ли лучший способ решить эту проблему?
Пожалуйста помоги
Рассматривали ли вы просто создание нового массива из существующего значения на реле, добавление, а затем вызов accept
?
myFilter.accept(myFilter.value + [newModel])
Я написал это расширение для замены Variable
на BehaviorRelay
s. Вы можете добавить любой метод, который вам нужен на основе этого шаблона, чтобы легко перенести.
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)
}
}
Вместо Variable.value.funcName
теперь вы пишете BehaviorRelay.funcName
.
Идея использовать, where Element: RangeReplaceableCollection
происходит от ответа ретендо
Также обратите внимание, что index
имеет тип Element.Index
, а не Int
или что-либо еще.
Основываясь на ответе Далтона, здесь есть удобное расширение:
extension BehaviorRelay where Element: RangeReplaceableCollection {
func acceptAppending(_ element: Element.Element) {
accept(value + [element])
}
}
Я бы сделал что-то подобное -
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)
Ответ AshKan отличный, но я пришел сюда в поисках недостающего метода из решения. Append:
extension BehaviorRelay where Element: RangeReplaceableCollection {
func append(_ subElement: Element.Element) {
var newValue = value
newValue.append(subElement)
accept(newValue)
}
}
Я создал это расширение с двумя способами, облегчающими миграцию, если у вас есть переменная массива и вам нужно использовать append.
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)
}
}
и ты называешь это так
var things = BehaviorRelay<[String]>(value: [])
things.append("aa")
let otherThings = ["bb", "cc"]
things.append(contentsOf: otherThings)
things.remove(at: 0)
things.removeAll()