I am fairly new to Rx and to Reactive Programming in general. I am simply trying to make things work. I'm trying to populate an object after a request to an API (Github's API for the matter):
The object to populate :
class GithubUser {
var login: String?
var joinDate: Date?
var email: String?
}
The way I try to feed it:
class GithubUserRepository {
static func getUser() -> Observable<GithubUser> {
let userObservable = BehaviorRelay<GithubUser>(value: GithubUser())
let login = "Thiryn"
// GithubService.sharedInstance.getUser does whatever async call to the github API to get a user profile
GithubService.sharedInstance.getUser(login, success: { (userProfile) in
userObservable.value.login = login
userObservable.value.email = userProfile.email
userObservable.value.joinDate = userProfile.joinedDate
}) { (error) in
print(error.localizedDescription)
}
return userObservable.asObservable()
}
}
And how I try to consume
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
GithubUserRepository.getUser().subscribe(onNext: { (user) in
print(user.login ?? "nope")
}).disposed(by: self.disposeBag)
}
}
The result is that I a "nope" the first time, before the request get executed, then I successfully get a result from my request, change the value of the object, but I might do something wrong as the subscribed function is never executed after. Any thoughts? Thanks!
Edit : I based my try on the Reactive Values example from RxSwift
A couple of clarifications -
First of all, the way to wrap an existing API service into an Observable would be to use Observable.create {}
. The way you're doing this at the moment is suboptimal (e.g. using a Relay just to store values)
Second, modifying a reference type isn't considered a "change" on the observable stream. The only thing that is considered a change is actually emitting a new value onto the stream. (e.g. relay.accept(newUser)
).
For your situation, the scheme you should follow would be:
func myMethod() -> Observable<DataModel> {
return Observable.create { observer in
myAPIService.doRequest ( result in
... do some stuff ...
observer.onNext(result)
observer.onCompleted()
// or observer.onError(error) if it occured
}
return Disposables.create { }
}
}
This is the proper way to wrap your API call inside a Rx-y method, that returns an Observable
object. You could do the same with Single.create
if you'd like to return a Single
.
You should read further on how Rx works, it is not as basic as manipulating the current "value" of things, as things in streams don't really have a "value", it is just values being continuously added into an existing stream.