简体   繁体   中英

RxSwift: tap a button to do a request with Alamofire, how to make it work?

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.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM