engin ipek
engin ipek

Reputation: 5

RxCocoa-observable is emitting new data from API but tableview.rx.items doesn't show new data

I am new to both RxSwift and RxCocoa.

I have a working REST service on local which returns a Movie object for given "id".

On my storyboard there is a tableView (UITableView) which has custom cells (MovieCell). Each movie cell has a UILabel named "nameTextLabel". I also have a textField to get requested movie.id from user.

I am trying to show movie.title on each row of my tableView.

import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {

@IBOutlet var textField: UITextField!
@IBOutlet var tableView: UITableView!
let bag = DisposeBag()

override func viewDidLoad() {
    super.viewDidLoad()
    configureReactiveBinding()
}
private func configureReactiveBinding() {
    textField.rx.text.asObservable()
        .map { ($0 == "" ? "15" : $0!).lowercased() }
        .map { GetMovieByIdRequest(id: $0) }
        .flatMap { request -> Observable<Movie> in
            return ServiceManager.instance.send(apiRequest: request)
        }
    .debug("movie")
// output:
//2018-10-17 16:13:49.320: movie -> subscribed
//2018-10-17 16:13:49.401: movie -> Event next(MovieAdvisor.Movie)
//2018-10-17 16:13:52.021: movie -> Event next(MovieAdvisor.Movie)
    .toArray()
    .debug("tableView")
// output:
//2018-10-17 16:13:49.318: tableView -> subscribed

        .bind(to: tableView.rx.items(cellIdentifier: "movie_cell", cellType:MovieCell.self)) { index, model, cell in
            cell.nameTextLabel.text = model.title
        }
        .disposed(by: bag)
}

}

Each time textLabel is changed the new movie.id is printed, but tableView doesn't show any data-not even with initial value (when textField is "").

Any idea how can i fix this?

After adding debug() lines, i figured that tableView is subscribed just once and no next events triggered tableView. What should i do? Code is uploaded on GitHub github

Upvotes: 0

Views: 581

Answers (2)

Maxim Volgin
Maxim Volgin

Reputation: 4077

Try replacing

`a.subscribe(onNext: {movie in
    print(movie.title)
})
.disposed(by: bag)

with .observeOn(MainScheduler.instance) and see whether it does the trick.

Perhaps move .toArray() to directly after ServiceManager.instance.send(apiRequest: request).

Also you can add *.debug("my custom message")* after every RxSwift operator to see whether it is getting executed.

BTW I would recommend using RxDataSources framework for this, not bare RxCocoa.

Upvotes: 1

Daniel T.
Daniel T.

Reputation: 33967

The problem is your toArray() operator. That operator waits until the sequence completes and then emits the entire sequence as a single array. Your sequence doesn't complete until after you have exited the view controller.

Replace that with .map { [$0] } instead and the movie will show. You should ask yourself though why your endpoint is only returning one movie instead of an array of movies.

Upvotes: 2

Related Questions