RxSwift 订阅者接收多个事件
Posted
技术标签:
【中文标题】RxSwift 订阅者接收多个事件【英文标题】:RxSwift Subscriber receiving multiple events 【发布时间】:2021-04-22 01:55:59 【问题描述】:考虑下面的代码。
-
在 tapButton 上,我们订阅 Observable
isFetched
,然后调用 fetchPopularMovies()
。
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()
【问题讨论】:
因为您每次点击按钮都会订阅 订阅就像报纸,一旦订阅,您将获得该报纸的所有未来版本。如果您订阅该报纸两到五次,您将获得两到五份该报纸。 在你的情况下 distinctuntilchanged @SPatel 谢谢。我喜欢报纸的比喻。 【参考方案1】:响应式代码是声明性的。这是“设置”代码。所以它应该放在评论说“加载视图后做任何额外的设置”的地方。
您可以做的最简单的更改来解决您遇到的问题是将订阅移动到 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
s 应始终与let
s 一起使用,而不是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
中。
【讨论】:
谢谢。移至 viewDidLoad() 并按预期工作。让我试试 RxCocoa。以上是关于RxSwift 订阅者接收多个事件的主要内容,如果未能解决你的问题,请参考以下文章