Reputation: 4037
I have some UI rx button tap, I want to connect it to the network rx part.
Here is Rx btn tap part:
btn.rx.tap.take(1).flatMap { [unowned self] () -> Observable<Bool> in
// ...
return NetManager.standard.request()
}.debug().do(onNext: { _ in
print("The data flows here")
}).flatMapLatest { (echo: Bool) -> Observable<Bool> in
if echo{
if let app = UIApplication.shared.delegate as? AppDelegate{
app.goHome()
}
return Observable.of(true)
}
else{
return Observable.of(false)
}
}.subscribe(onNext: { (result) in
// ... , do sth with result
}).disposed(by: rx.disposeBag)
Here is net request part with Alamofire:
class NetManager: NSObject {
static let standard = NetManager()
var dataRequest: DataRequest?
func request() -> Observable<Bool> {
return Observable<Bool>.create{ (observer) -> Disposable in
let data = // ...
// ...
self.dataRequest = AF.request(aURL, method: HTTPMethod.post, parameters: data, encoder: JSONParameterEncoder.prettyPrinted, headers: aHead).response { (response: DataResponse<Data?>) in
self.hud?.hide()
if let data = response.data{
observer.onNext(true)
// ....
}
else{
observer.onNext(false)
}
}
observer.onCompleted()
return Disposables.create{}
}
}
}
Here is the debug info:
Controller.swift:141 (viewDidLoad()) -> subscribed
Controller.swift:141 (viewDidLoad()) -> Event completed
Controller.swift:141 (viewDidLoad()) -> isDisposed
The result is , the do( next )
part seems like that it has not been called. Because no print
in console.
The question is, how to make the rx logic work?
Here is what I tried:
turn btn.rx.tap.flatMap
to btn.rx.tap.take(1).flatMap
because from this issue
if a flatMap completion would terminate the outer stream, it would mean that no more button taps would be registered in your stream, which don't really make sense.
Seen from this question
btn.rx.tap.map { () -> Observable<Bool> in
return NetManager.standard.request()
}.flatMapLatest { (observer: Observable<Bool>) -> Observable<Bool> in
// of cource, I can subscribe to observer
/*
observer.subscribe(onNext: { (echo) in
})
*/
// how to get the event element elegantly.
return Observable.of(false)
}.subscribe(onNext: { (_) in
}).disposed(by: rx.disposeBag)
how to do this more elegantly.
Upvotes: 3
Views: 931
Reputation: 607
The main issue here is that when performing the network request, you are not waiting for the network call to respond. So observer.onComplete()
is triggered before observer.onNext()
class NetManager: NSObject {
static let standard = NetManager()
var dataRequest: DataRequest?
func request() -> Observable<Bool> {
return Observable<Bool>.create { (observer) -> Disposable in
let data = // ...
// ...
self.dataRequest = AF.request(aURL, method: HTTPMethod.post, parameters: data, encoder: JSONParameterEncoder.prettyPrinted, headers: aHead).response { (response: DataResponse<Data?>) in
self.hud?.hide()
if let data = response.data {
observer.onNext(true)
// ...
}
else {
observer.onNext(false)
}
observer.onComplete() // Moving it here instead will wait for the response
}
return Disposables.create { }
}
}
}
At this point, your code should work as it is, but you're still overcomplicating a very simple thing.
Here is what to do:
btn.rx.tap
.flatMap { _ in
return NetManager.standard.request()
}
.subscribe(onNext: { (success) in
if success {
if let app = UIApplication.shared.delegate as? AppDelegate {
app.goHome()
}
}
})
.disposed(by: rx.disposeBag)
Upvotes: 2