1

I am currently trying to learn Rx programming. I found Moya intriguing and have been trying to implement a simple network request which then gets mapped to objects which I can then use to populate a tableView.

I have been following this tutorial: http://www.thedroidsonroids.com/blog/ios/rxswift-examples-3-networking/

I believe I am getting a successful response as I am using .debug and getting the following output:

2016-04-09 13:29:30.398: MyApi.swift:37 (findRepository) -> subscribed
2016-04-09 13:29:30.400: MyApi.swift:35 (findRepository) -> subscribed
2016-04-09 13:29:32.633: MyApi.swift:35 (findRepository) -> Event Next(Status Code: 20..., Data Length: 5747)
2016-04-09 13:29:32.633: MyApi.swift:35 (findRepository) -> Event Completed

Here is the code that I am using:

let provider: RxMoyaProvider<MyApi>
let repositoryName: Observable<String>

func trackIssues() -> Observable<[Train]> {
    return repositoryName
        .observeOn(MainScheduler.instance)
        .flatMapLatest { name -> Observable<[Train]?> in
            print("Name: \(name)")

            return self.findRepository(name)
        }.replaceNilWith([])
}

internal func findRepository(name: String) -> Observable<[Train]?> {
    print("help")
    return self.provider
        .request(MyApi.Trains(name, "c76a46ce2b3d8685982b/raw/10e86080c3b1beedd46db47f5bb188cc74ce5c78/sample.json"))
        .debug()
        .mapArrayOptional(Train.self)
        .debug()
}

And here is the object I am trying to map to:

import Mapper

struct Train: Mappable {

    let distance: String
    let eta: String

    init(map: Mapper) throws {
        try distance = map.from("distance")
        try eta = map.from("eta")
    }
}

I have looked at the network response and am wondering if I first need to abstract the "trains" data. I have tried this by mapping to the following object with out luck:

import Mapper

struct TrainsResponse: Mappable {

    let trains: String

    init(map: Mapper) throws {
        try trains = map.from("trains")
    }
}

Please find example json response here: http://pastebin.com/Wvx8d5Lg

So I was wondering if anyone can help me see why I am unable to turn the response into objects. Thanks.

=======

I have tried doing a pod update and it's still not working. Here is where I am binding it to the tableView:

func setupRx() {
    // First part of the puzzle, create our Provider
    provider = RxMoyaProvider<MyApi>()

    // Now we will setup our model
    myApi = MyApi(provider: provider, repositoryName: userName)

    // And bind issues to table view
    // Here is where the magic happens, with only one binding
    // we have filled up about 3 table view data source methods
    myApi
        .trackIssues()
        .bindTo(tableView.rx_itemsWithCellFactory) { (tableView, row, item) in
            let cell = tableView.dequeueReusableCellWithIdentifier("issueCell", forIndexPath: NSIndexPath(forRow: row, inSection: 0))
            cell.textLabel?.text = "Hello"

            print("Hello")

            return cell
        }
        .addDisposableTo(disposeBag)
}

The code inside bind to (where I set the cell) never gets called. Also if I put a break point inside my Train mapper class that also never gets called.

pls
  • 1,522
  • 2
  • 21
  • 41
  • 1
    Can you try updating pods? If it doesn't help, the requests seems OK because you get the 200 response. How do you bind the `trackIssues()` to UI? – sunshinejr Apr 09 '16 at 13:49
  • Thanks for the response. I did a pod update but that didn't work. I have edited code to include where I am binding trackIssues() to UI. – pls Apr 09 '16 at 14:04
  • 1
    If the array is in "trains" key, try using `.mapArrayOptional(Train.self, keyPath: "trains")`, instead of `.mapArrayOptional(Train.self)`. – sunshinejr Apr 09 '16 at 14:53
  • 1
    That works. Thanks a lot :-). – pls Apr 09 '16 at 15:26
  • No problem! I've made an answer to help other people that encounters the same problem as well. – sunshinejr Apr 09 '16 at 15:37

1 Answers1

2

The reason it doesn't work is that the JSON retrieved from the server returns dictionary, not an array. The array you wanted to parse is under the "trains" key in that dictionary. The Moya-ModelMapper used in the tutorial has methods for this usage as well. You just need to pass second argument, keyPath: in a mapArrayOptional() method.

So the answer for your question is replace:
.mapArrayOptional(Train.self)
with
.mapArrayOptional(Train.self, keyPath: "trains")

sunshinejr
  • 4,834
  • 2
  • 22
  • 32
  • Hi can ask how can we handle nested json? for example the data needed for the model is behind a few nested json in the json response. And can help me with this question? many thank http://stackoverflow.com/questions/43228253/ios-construct-moya-targettype – Lê Khánh Vinh Apr 05 '17 at 10:42