我试图定期(每10秒)调用一个返回模型的Json对象的API:
struct MyModel { 
   var messagesCount: Int?
   var likesCount: Int?
}如果messageCount或likesCount值发生更改,则更新UI。我尝试了计时器解决方案,但我发现它有点混乱,我想要一个更干净的解决方案与RxSwift和RxAlamofire。
任何帮助都是非常感谢的,因为我是Rx的新手。
发布于 2018-09-13 12:31:22
欢迎来到StackOverflow!
这需要相当多的操作符,我建议在ReactiveX运算符页上查找它们,每次我忘记一些东西时都会检查它。
首先,确保MyModel符合Decodable,这样就可以从JSON响应构建它(参见可编)。
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)然后,您可以继续数据流到您的UI元素。
myModelObservable
    .map { $0.messagesCount }
    .map { "\($0) messages" }
    .bind(to: yourLabel.rx.text }
    .disposed(by: disposeBag)我没有运行这段代码,所以这里可能有一些输入/缺少转换,但这应该会指向正确的方向。请随时要求澄清。如果Rx是真正的新手,我建议您通过入门指南。太棒了!Rx非常强大,但我花了一段时间才掌握。
编辑
正如@daniel所指出的,在使用Observable<Int>.interval时,后台/前台簿记是不必要的。
发布于 2018-09-13 23:55:18
CloakedEddy与他的回答非常接近,理应得到更多选票。然而,他把事情弄得比必要的复杂一些。Interval在内部使用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.https://stackoverflow.com/questions/52311965
复制相似问题