Повторите последний запрос с помощью RxSwift - PullRequest
0 голосов
/ 24 января 2019

Я создаю сетевой уровень, где я внедряю API-провайдер и вызываю событие для метода initialize.

class NetworkingLayer<T: Decodable, E: TargetType> {

    var response: Driver<T>

    init(provider: MoyaProvider<E>, request: Singal<E>) {

        let requestState = request
            .flatMapLatest({
                provider.rx.request($0).map(Respose<T>.self)
                    .map { ReqestState.loaded($0) }
                    .asDriver(onErrorRecover: { error  in
                        return Driver.just(.error(error))
                    })
                    .startWith(.loading)
            })
            .asDriver(onErrorRecover: { fatalError($0.localizedDescription) })

        response = requestState
            .map({ $0.data?.data })
            .filterNil()

    }
}

Используя их следующим образом:

class ViewModel {

    let networking: DataNetworkingResponse<[TagItem], ScoutEnpoint>

    init(provider: MoyaProvider<Endpoint>, event: Singal<[Int]>) {

        let request = event
            .map({ Endpoint.getNewItems(prevItemsIds: $0) })

        self.networking = NetworkingLayer(provider: provider, request: request)
    }
}

Все работает как шарм. Но теперь я должен реализовать функцию обновления. Обновить мой последний запрос. Я добавил это свойство let refresh: Signal<()> = Signal.empty() на свой сетевой уровень. Но не могу понять, как сохранить мой последний запрос.

class NetworkingLayer<T: Decodable, E: TargetType> {

    let refresh: BehaviorRelay<()> = BehaviorRelay.init(value: ())
    ...
}

Как я могу реализовать обновление таким образом?

viewModel.networking.refresh.accept(())

1 Ответ

0 голосов
/ 24 января 2019

Использование BehaviorRelay - плохая идея, поскольку оно выдает значение, как только оно подписано. Это означает, что ваш NetworkingLayer объект сделает запрос, как только будет создан.

Лучше было бы передать другой сигнал в метод init:

init(provider: MoyaProvider<E>, request: Singal<E>, refresh: Signal<Void>)

Я не знаю, Мойя, но вот как бы я написал что-то подобное, используя URLSession:

enum RequestState<T> {
    case loaded(T)
    case error(Error)
    case loading
}

class NetworkingLayer<T: Decodable> {

    let response: Driver<RequestState<T>>

    init(request: Signal<URLRequest>, refresh: Signal<Void>, provider: URLSession = URLSession.shared, decoder: JSONDecoder = JSONDecoder()) {
        response = Observable.merge(request.asObservable(), refresh.withLatestFrom(request).asObservable())
            .flatMapLatest { request in
                provider.rx.data(request: request)
                    .map { try decoder.decode(T.self, from: $0) }
                    .map { RequestState.loaded($0) }
                    .startWith(.loading)
                    .catchError { Observable<RequestState<T>>.just(.error($0)) }
            }
            .share(replay: 1)
            .asDriver(onErrorRecover: { fatalError($0.localizedDescription) })
    }
}

Я добавил туда share(replay:), чтобы последующие подписчики не делали отдельные сетевые запросы, и я сделал декодер инъекционным, чтобы звонящий мог настроить его так, как он хочет.

...