0

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

  • I need some information to help you... Put a `.debug("tableView")` between your `.toArray()` and you're `.bind(to:)`. Add the output of that debug statement to your question. – Daniel T. Oct 17 '18 at 11:59
  • thanks for quick reply! added debug commands, I hope this helps you to solve the issue. – engin ipek Oct 17 '18 at 13:24

2 Answers2

2

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.

Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • when i replace toArray() with .map { [$0] } , i got "Generic parameter self cannot be inferred" compile time error. The reason why my endpoint is only returning 1 movie is, because it is getMovieById, so it is only returning the movie with the given id. Why you suggest that? Is it better to work with arrays when using Observables? – engin ipek Oct 17 '18 at 15:14
  • Odd, I pulled down your GitHub project and made the replacement and it worked perfectly. A tableview displays an array which is why I was surprised that the stream that feeds the tableview was only emitting a single value. – Daniel T. Oct 18 '18 at 00:06
1

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.

Maxim Volgin
  • 3,957
  • 1
  • 23
  • 38
  • thanks for debug() suggestion. Observing on main scheduler didn't help though :( – engin ipek Oct 17 '18 at 13:12
  • Perhaps move '.toArray()' to directly after 'ServiceManager.instance.send(apiRequest: request)' – Maxim Volgin Oct 17 '18 at 13:16
  • I did, thanks! The reason behind it that `.toArray()` waits for the whole thing to complete (which never happens), but you need it to emit after every service request. – Maxim Volgin Oct 17 '18 at 14:02