Как использовать BehaviorRelay в качестве альтернативы переменной в RxSwift?

по состоянию на RxSwift4,Variable переехал в Deprecated.swift маркировка возможного осуждения Variable в будущем. Альтернативный предложил Variable is BehaviorRelay. При публикации этого вопроса, так как я не смог найти большую часть учебника в интернете с помощью BehaviorRelay размещаю такой фундаментальный вопрос здесь в SO.

предположим, что у меня есть вызов webService, и я получаю кусок данных, который является JSONArray, при разборе объекта JSON один за другим Я обновляю значение своей переменной собственность

вот мое объявление переменной

var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data: "{:}")])

при получении нового элемента каждый раз, когда я буду обновлять свою переменную как

myFilter.value.append(newModel)

поскольку переменная была привязана к CollectionView, collectionVie немедленно обновит свой пользовательский интерфейс новым добавленным объектом.

проблема с BehaviorRelay

теперь моя декларация выглядит как

var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data: "{:}")])

но самая большая проблема-это myFilter.value is только для чтения. Так что, очевидно,

myFilter.value.append(newModel) 

это не решение. Я понял, что могу использовать accept а.

но теперь, когда я пытаюсь проанализировать каждый элемент в ответ и обновить значение myFilter

self?.expertsFilter.accept(newModel)

приведенное выше утверждение дает ошибку quoting

не удается преобразовать значение параметра NewModel в ожидаемый тип аргумента [NewModel]

очевидно, что он ожидает массив, а не отдельный элемент.

решение:

Решение 1:

таким образом, одно решение накапливает весь ответ во временном массиве и после того, как триггерself?.expertsFilter.accept(temporary_array)

решение 2:

если я должен отправить onNext событие для подписчика при разборе каждого элемента мне нужно скопировать значение self?.expertsFilter в новый массив, добавьте в него вновь проанализированный элемент и верните новый матрица.

решение 3:

избавиться BehaviorRelay и использовать BehaviorSubject/PublishSubject

первые два звука удручают, потому что может возникнуть необходимость запускать UI при разборе каждого элемента, я не могу ждать, пока весь ответ будет проанализирован. Поэтому очевидно, что решение 1 не очень полезно.

второе решение намного ужаснее, потому что оно создает новый массив (я знаю его временный и будет выпущен) каждый раз, чтобы отправить onNext событие.

вопрос:

, потому что BehaviorRelay предлагается в качестве альтернативного Variable Я в дилемме, я использую accept правильно?? Есть ли лучший способ решить эту проблему?

пожалуйста, помогите

3 ответов


вы рассматривали просто создание нового массива из существующего значения на ретрансляторе, добавление, а затем вызов accept?

myFilter.accept(myFilter.value + [newModel])

дом на ответ Далтона, вот удобное расширение:

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().map { parse() }.toArray() }

parsed.bind(to: ui)

// repeated part
let request1: Observable<ServerResponse> = servive.call()
request.onNext(request1)