Периодически вызывать API с помощью RxSwift - PullRequest
0 голосов
/ 13 сентября 2018

Я пытаюсь периодически (каждые 10 секунд) вызывать API, который возвращает объект Json модели:

struct MyModel { 
   var messagesCount: Int?
   var likesCount: Int?
}

И обновлять пользовательский интерфейс, если значение messageCount или likesCount изменяется.Я попробовал решение с таймером, но я нахожу его немного грязным, и я хочу более чистое решение с RxSwift и RxAlamofire.

Любая помощь высоко ценится, поскольку я новичок в Rx.

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

CloakedEddy очень близко подошел к своему ответу и заслуживает голосов. Однако он сделал это немного сложнее, чем необходимо. Интервал использует DispatchSourceTimer внутри, который автоматически останавливается и перезапускается, когда приложение переходит в фоновый режим и возвращается на передний план. Он также отлично поработал, вспомнив, что перехватил поток, чтобы остановить раскручивание потока.

Я предполагаю, что приведенный ниже код находится в AppDelegate или Координаторе высокого уровня. Кроме того, myModelSubject является ReplaySubject<MyModel> (создайте его с помощью: ReplaySubject<MyModel>.create(bufferSize: 1), который должен быть размещен где-то, к которому контроллеры представления имеют доступ или передаются для просмотра контроллеров.

Observable<Int>.interval(10, scheduler: MainScheduler.instance) // fire at 10 second intervals.
    .flatMapLatest { _ in
        RxAlamofire.requestData(.get, yourUrl) // get data from the server.
            .catchError { _ in .empty() }   // don't let error escape.
    }
    .map { $0.1 } // this assumes that alamofire returns `(URLResponse, Data)`. All we want is the data.
    .map { try? JSONDecoder().decode(MyModel.self, from: $0) } // this assumes that MyModel is Decodable
    .filter { $0 != nil } // filter out nil values
    .map { $0! } // now that we know it's not nil, unwrap it.
    .bind(to: myModelSubject) // store the value in a global subject that view controllers can subscribe to.
    .disposed(by: bag) // always clean up after yourself.
0 голосов
/ 13 сентября 2018

Добро пожаловать в StackOverflow!

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

Прежде всего, убедитесь, что MyModel соответствует Decodable, поэтому его можно построить из ответа JSON (см. Codable ).

let willEnterForegroundNotification = NotificationCenter.default.rx.notification(.UIApplicationWillEnterForeground)
let didEnterBackgroundNotification = NotificationCenter.default.rx.notification(.UIApplicationDidEnterBackground)

let myModelObservable = BehaviorRelay<MyModel?>(value: nil)

willEnterForegroundNotification
    // discard the notification object
    .map { _ in () }
    // emit an initial element to trigger the timer immediately upon subscription
    .startWith(())
    .flatMap { _ in 
        // create an interval timer which stops emitting when the app goes to the background
        return Observable<Int>.interval(10, scheduler: MainScheduler.instance)
            .takeUntil(didEnterBackgroundNotification)
    }
    .flatMapLatest { _ in 
        return RxAlamofire.requestData(.get, yourUrl)
            // get Data object from emitted tuple
            .map { $0.1 } 
            // ignore any network errors, otherwise the entire subscription is disposed
            .catchError { _ in .empty() } 
    } 
    // leverage Codable to turn Data into MyModel
    .map { try? JSONDecoder().decode(MyModel.self, from: $0) } }
    // operator from RxOptional to turn MyModel? into MyModel
    .filterNil() 
    .bind(to: myModelObservable)
    .disposed(by: disposeBag)

Затем, вы можете просто продолжить поток данных в ваши элементы пользовательского интерфейса.

myModelObservable
    .map { $0.messagesCount }
    .map { "\($0) messages" }
    .bind(to: yourLabel.rx.text }
    .disposed(by: disposeBag)

Я не запускал этот код, поэтому здесь могут быть некоторые опечатки / пропущенные преобразования, но это должно указать вам на правонаправление.Не стесняйтесь просить разъяснений.Если действительно новичок в Rx, я рекомендую просмотреть руководство Getting Started .Это великолепно!Rx очень мощный, но мне потребовалось некоторое время, чтобы понять.

Edit

Как указал @ daniel-t, при использовании Observable<Int>.interval ведение бухгалтерии фона / переднего плана не требуется.1026 *

...