I am trying to understand RxSwift
. I have created a simple playground below that mocks out the behaviour I am attempting. This should run OK.
import UIKit
import RxSwift
struct Universities: Codable {
let author: Author
let example: String
let github: String
enum CodingKeys: String, CodingKey {
case author
case example
case github
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
author = try values.decode(Author.self, forKey: .author)
example = try values.decode(String.self, forKey: .example)
github = try values.decode(String.self, forKey: .github)
}
}
struct Author: Codable {
let name: String
let website: String
enum CodingKeys: String, CodingKey {
case name
case website
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
website = try values.decode(String.self, forKey: .website)
}
}
class HTTPClient<T: Codable> {
private let baseURL = URL(string: "http://universities.hipolabs.com/")!
func call() -> Observable<T> {
return Observable<T>.create { observer in
let request = URLRequest(url: self.baseURL)
let task: URLSessionDataTask = URLSession.shared.dataTask(with: request) { data, response, error in
do {
let model: T = try JSONDecoder().decode(T.self, from: data!)
observer.onNext(model)
} catch let error {
observer.onError(error)
}
observer.onCompleted()
}
task.resume()
return Disposables.create {
task.cancel()
}
}
}
}
class SomeService {
private let client = HTTPClient<Universities>()
private let disposeBag = DisposeBag()
func getValues() {
client.call().subscribe(onNext: { print($0.example) }).disposed(by: disposeBag)
}
}
let service = SomeService()
service.getValues()
As you can see SomeService
calls my http client which makes a request and returns the response. I then print out a value. What I'm struggling to understand is how can I subscribe to getValues
in another class, and make use of the response.
This was my current attempt
class SomeService {
private let client = HTTPClient<Universities>()
private let disposeBag = DisposeBag()
func getValues() -> Observable<String> {
return client.call().subscribe(onNext: { return $0.example }).disposed(by: disposeBag)
}
}
let service = SomeService()
service.getValues().map { print($0) }
However I get an error
Cannot convert return expression of type '()' to return type 'Observable'
Should I be creating some sort of subject and subscribing to that from my controller and instead calling onNext
with the returned value?
If so how would I structure those calls in my controller?
func getValues() -> Observable<String> {
return client.call()
.map { $0.example }
.do(onNext: { print($0) })
}
No need to introduce an in between subject. Do onNext will hook on the observable and add the printing behavior you desire. map will transform the universities type to the example string. Then you can simply subscribe to the result of getValues()
from your ViewController.