anakyn
anakyn

Reputation: 17

RxSwift wait for observable to complete, and return observable

When I use loadMovies function I get desired movies only after the ViewController has called function and disposed it, this function is inside API

func loadMovies() -> Observable<[Movie]> {
    let obsMovies = self.APICall(genrePath: Movies.action, structType: Movie.self)
    return Observable.create{ observer -> Disposable in
        obsMovies.subscribe(
            onNext: { element in 
                      observer.onNext(element)
                      print(element) 
           }
        )
        observer.onCompleted()
        return Disposables.create()
    }
}

In ViewController I call this function inside viewDidLoad


request.api.loadMovies()
    .debug()
    .subscribe(
        onNext:{ data in
            do {
                print(data)
            }
        },
        onError: { error in
            print(error)
        },
        onCompleted: {
            print("Completed")
        },
        onDisposed: {
            print("Disposed")
        }
    )
    .disposed(by: disposeBag)

and get this output

ViewController.swift:55 (viewDidLoad()) -> subscribed
ViewController.swift:55 (viewDidLoad()) -> Event completed
Completed
Disposed
ViewController.swift:55 (viewDidLoad()) -> isDisposed

[MovieTest.Movie(name: "Black Panther", year: "2018", rating: "83")]
[MovieTest.Movie(name: "AVENGERS: ENDGAME", year: "2019", rating: "90")]
[MovieTest.Movie(name: "MISSION: IMPOSSIBLE -- FALLOUT", year: "2018", rating: "88")]...

I want to how to wait for function to fetch movies before being disposed.I want to display everything in tableView. I'm beginner at RxSwift, I believe there is better way to achieve this but as of right now I have no idea. Thanks

Upvotes: 1

Views: 1930

Answers (1)

Daniel T.
Daniel T.

Reputation: 33979

So there are a couple of problems to fix right away... obsMovies.subscribe() returns a disposable that you are ignoring. Since the closure it's embedded in needs to return a disposable, how about just returning the one that subscribe created instead of making a new one:

func loadMovies() -> Observable<[Movie]> {
    let obsMovies = self.APICall(genrePath: Movies.action, structType: Movie.self)
    return Observable.create{ observer -> Disposable in
        let disposable = obsMovies.subscribe(
            onNext: { element in
                observer.onNext(element)
                print(element)
            }
        )
        observer.onCompleted()
        return disposable
    }
}

Next, notice that APICall(genrePath:structType:) returns an Observable<[Movie]> so why not just return that rather than wrapping it in yet another Observable?

func loadMovies() -> Observable<[Movie]> {
    return self.APICall(genrePath: Movies.action, structType: Movie.self)
}

Wow, now I kind of wonder why loadMovies() exists at all... 🤔

So now that I have done the above, here's the output I see:

ViewController.swift:55 (viewDidLoad()) -> subscribed
ViewController.swift:55 (viewDidLoad()) -> Event next([MovieTest.Movie(name: "Black Panther", year: "2018", rating: "83"), MovieTest.Movie(name: "AVENGERS: ENDGAME", year: "2019", rating: "90"), MovieTest.Movie(name: "MISSION: IMPOSSIBLE -- FALLOUT", year: "2018", rating: "88")])
[MovieTest.Movie(name: "Black Panther", year: "2018", rating: "83"), MovieTest.Movie(name: "AVENGERS: ENDGAME", year: "2019", rating: "90"), MovieTest.Movie(name: "MISSION: IMPOSSIBLE -- FALLOUT", year: "2018", rating: "88")]
ViewController.swift:55 (viewDidLoad()) -> Event completed
Completed
Disposed
2021-04-11 20:05:08.356: Stuff.swift:55 (viewDidLoad()) -> isDisposed

Upvotes: 1

Related Questions