Narek  Simonyan Narek Simonyan - 5 months ago 86
Swift Question

RxSwift: code working only first time

I'm new in RxSwift. Some strange thing happens in my code.
I have a collection view and


Driver["String"]


Data for binding.

var items = fetchImages("flower")
items.asObservable().bindTo(self.collView.rx_itemsWithCellIdentifier("cell", cellType: ImageViewCell.self)) { (row, element, cell) in
cell.imageView.setURL(NSURL(string: element), placeholderImage: UIImage(named: ""))
}.addDisposableTo(self.disposeBag)



fetchImages


Function returns data

private func fetchImages(string:String) -> Driver<[String]> {

let searchData = Observable.just(string)
return searchData.observeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background))
.flatMap
{ text in // .Background thread, network request

return RxAlamofire
.requestJSON(.GET, "https://pixabay.com/api/?key=2557096-723b632d4f027a1a50018f846&q=\(text)&image_type=photo")
.debug()
.catchError { error in
print("aaaa")
return Observable.never()
}
}
.map { (response, json) -> [String] in // again back to .Background, map objects
var arr = [String]()
for i in 0 ..< json["hits"]!!.count {
arr.append(json["hits"]!![i]["previewURL"]!! as! String)
}

return arr
}
.observeOn(MainScheduler.instance) // switch to MainScheduler, UI updates
.doOnError({ (type) in
print(type)
})
.asDriver(onErrorJustReturn: []) // This also makes sure that we are on MainScheduler
}


Strange thing is this. First time when I fetch with "flower" it works and return data, but when I add this code

self.searchBar.rx_text.subscribeNext { text in
items = self.fetchImages(text)
}.addDisposableTo(self.disposeBag)


It doesn't work. It doesn't steps in flatmap callback, and because of this, doesn't return anything.

Answer

It works in your first use case, because you're actually using the returned Driver<[String]> via a bindTo():

var items = fetchImages("flower")
items.asObservable().bindTo(...

However, in your second use case, you aren't doing anything with the returned Driver<[String]> other than saving it to a variable, which you do nothing with.

items = self.fetchImages(text)

A Driver does nothing until you subscribe to it (or in your case bindTo).

EDIT: To make this clearer, here's how you could get your second use case to work (I've avoided cleaning up the implementation to keep it simple):

self.searchBar.rx_text
.flatMap { searchText in
    return self.fetchImages(searchText)
}
.bindTo(self.collView.rx_itemsWithCellIdentifier("cell", cellType: ImageViewCell.self)) { (row, element, cell) in
    cell.imageView.setURL(NSURL(string: element), placeholderImage: UIImage(named: ""))           
}.addDisposableTo(self.disposeBag)