簡體   English   中英

RxSwift 訂閱者接收多個事件

[英]RxSwift Subscriber receiving multiple events

考慮下面的代碼。

  1. 在 tapButton 上,我們訂閱一個 Observable isFetched ,然后調用fetchPopularMovies()
  2. fetchPopularMovies()依次調用 API。 當收到響應時,我們將發送OnNext(true)事件。

問題是,我在第二個按鈕點擊后收到多個事件。 如果我添加 onCompleted(),我什至不會在第二個按鈕點擊時收到事件。 我的期望是每次點擊按鈕都會觸發一個事件。 我在這里想念什么?

class ViewController: UIViewController {

    let popularMoviesURL = URL(string: "https://api.themoviedb.org/3/movie/popular?api_key=API_KEY")
    var isFetched = BehaviorSubject<Bool?>(value:nil)
    let disposeBag = DisposeBag()
        
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func tapButton(_ sender: Any) {
        let observable = isFetched.asObservable()
        observable.subscribe(onNext: { observer in
            guard let result = observer else { return }
            print(result)
            print("onNext Recieved")
            
        }, onError: { _ in
            print("onError Recieved")
        }).disposed(by: disposeBag)
        
        fetchPopularMovies()
    }
    
    func fetchPopularMovies() {
        let task = URLSession.shared.dataTask(with: popularMoviesURL!) {(data, response, error) in
            guard let _ = data else { return }
            self.isFetched.onNext(true)
           //self.isFetched.onCompleted()
        }
        task.resume()
    }
}

反應式代碼是聲明性的。 這是“設置”代碼。 所以它應該放在評論說“加載視圖后做任何額外的設置”的地方。

您可以做的最簡單的更改來解決您遇到的問題是將訂閱移動到viewDidLoad方法中,正如 Satish Patel 在他的評論中引用的那樣。

override func viewDidLoad() {
    super.viewDidLoad()
    isFetched.subscribe(onNext: { observer in
        guard let result = observer else { return }
        print(result)
        print("onNext Recieved")

    }, onError: { _ in
        print("onError Recieved")
    }).disposed(by: disposeBag)
}

@IBAction func tapButton(_ sender: Any) {
    fetchPopularMovies()
}

(請注意, Subject應該始終與let s never var s 保持一致。)

如果你使用 RxCocoa,你可以進一步簡化這段代碼:

class ViewController: UIViewController {
    let button = UIButton()
    let isFetched = BehaviorSubject<Bool?>(value:nil)
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let popularMoviesURL = URL(string: "https://api.themoviedb.org/3/movie/popular?api_key=API_KEY")!

        let fetchedData = button.rx.tap
            .flatMapLatest {
                URLSession.shared.rx.data(request: URLRequest(url: popularMoviesURL))
                    .catch { error in
                        print("onError Recieved")
                        return Observable.empty()
                    }
            }

        fetchedData
            .map { _ in true }
            .bind(to: isFetched)
            .disposed(by: disposeBag)
    }
}

現在,您的所有代碼都是“設置代碼”,所以它們都在viewDidLoad中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM