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.
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")