RXSwift Not subscribing on Main Thread - ios

I am trying to make several API calls and populate a Realm Database.
Everything works fine. However when I try to run performSegue() on subscribe() method an exception is raised, informing that I can't do this on a background thread, which is perfectly reasonable.
But since I am subscribing to MainScheduler.instance shouldn't the subscribe() method run on UI Thread?
Single.zip(APIClient.shared.getSchools(), APIClient.shared.getPointsOfInterest())
.observeOn(SerialDispatchQueueScheduler(qos: .background))
.flatMap { zip in return Single.zip(SchoolDao.shared.insertSchools(schoolsJson: zip.0), PointOfInterestDao.shared.insertPointsOfInterest(poisJson: zip.1))}
.flatMap{ _ in Single.zip(SchoolDao.shared.countSchools(), PointOfInterestDao.shared.countPointsOfInterest())}
.subscribeOn(MainScheduler.instance)
.subscribe(onSuccess: { tableCounts in
let (schoolsCount, poisCount) = tableCounts
if(schoolsCount != 0 && poisCount != 0){
print(Thread.isMainThread) //Prints False
self.performSegue(withIdentifier: "splashToLogin", sender: nil)
}
}, onError: {
error in return
}).disposed(by: disposeBag)
Am I making a wrong assumption on how does RXSwift works?
Edit: If I add this line .observeOn(MainScheduler.instance) after .subscribeOn(MainScheduler.instance) the subscribe method runs on Main thread. Is this correct behavior? What is .subscribeOn(MainScheduler.instance) even doing?

Your edit explains all. Your initial assumption on what subscribeOn and observeOn were backwards.
The subscribeOn operator refers to how the observable above the operator in the chain subscribes to the source of events (and likely doesn't do what you think it does in any case. Your two network calls likely set up their own background thread to emit values on regardless of how they are subscribed to.)
For example, look at this:
extension ObservableType {
func subscribeOnMain() -> Observable<Element> {
Observable.create { observer in
let disposable = SingleAssignmentDisposable()
DispatchQueue.main.async {
disposable.setDisposable(self.subscribe(observer))
}
return disposable
}
}
}
It makes it obvious why the operator is called subscribeOn. It's because the subscribe is happening on the scheduler/thread in question. And this helps you understand better what is happening when you stack subscribeOn operators...
The observeOn operator refers to the scheduler that will be emitting elements to the observer (which is the block(s) of code that are passed to the subscribe operator.)
Which would look like this:
extension ObservableType {
func observeOnMain() -> Observable<Element> {
Observable.create { observer in
self.subscribe { event in
DispatchQueue.main.async {
observer.on(event)
}
}
}
}
}
From this you can see that the subscribe is happening on the original scheduler, while the observer is being called on the new scheduler.
Here is a great article explaining the whole thing: http://rx-marin.com/post/observeon-vs-subscribeon/

Related

Purpose of Disposables.create() in RxSwift

I'm learning RxSwift and I've come across the following pattern when creating Observables:
return Observable.create { observer in
let disposable = Disposables.create()
// Do some stuff with observer here
return disposable
}
As far as I can tell the returned Disposable doesn't actually do anything, does it serve a purpose other than to meet the requirements of the API to return a Disposable?
Is there any scenario where you might need to return a configured Disposable?
I suppose the thing that's confusing me the most is that the returned Disposable seems separate from the implementation of the Observable being created, i.e. it's not assigned to any properties or passed anywhere it's just created and returned.
There are two variations of the create method in relation to Disposables.
The first one, as Daniel mentioned, is used when you create a new Observable; you'll use the Disposables.create { ... } closure to "do cleanup", basically.
This is highly useful when using flatMapLatest, as your previous request will be disposed when a new ones comes in. Whenever it would be disposed, that "clean up" block will be called.
Observable<Int>.create { observer in
let someRequest = doSomeLongRunningThing { result in
observer.onNext(result)
observer.onCompleted()
}
return Disposables.create {
// How can I "cleanup" the process?
// Cancel the request, for example.
someRequest.cancel()
}
}
The second variation of Disposables.create is used for an entirely different purpose - grouping several Disposable objects as a single disposable object (a CompositeDisposable).
For example:
let disposable1 = someAction()
let disposable2 = someOtherAction()
let compositeDisposable = Disposables.create(disposable1, disposable2)
The Disposables.create function takes an optional closure. You should put any cancelation code in that closure. If you don't have any way to cancel, then the code is empty.
A good example is the wrapper around URLSession's dataTask method. In non-Rx code when you call URLRequest.shared.dataTask it returns a URLSessionDataTask object which can be used to cancel the network call. That object's cancel function gets called in the disposable.
Another common use is when you subscribe to some other observable from within your create closure. You then have to pass the disposable from that/those subscriptions by returning a Disposables.create(myDisposable) So that those subscriptions will get canceled properly when your Observable is disposed of.

RxSwift: Why does flatMapLatest never execute onCompleted()?

In my Swift UIViewController, I'm attempting to subscribe to a class member of type Variable, run it through a flatMapLatest call, and then have the onCompleted() call in the flatMapLatest observable execute on all subscribers. However, while onNext() is called, onCompleted() never is and I'm not sure why.
My class member is defined as:
private let privateVar = Variable<String>("")
while in my viewDidLoad() method, I set up the observables:
let localVar = self.privateVar.asObservable().distinctUntilChanged()
localVar.subscribe(onNext: { [weak self] sent in print("first onNext called") })
.disposed(by: self.disposeBag)
let mappedVar = localVar.flatMapLatest { self.ajaxLoad(var1: $0) }.share()
mappedVar.subscribe(
onNext: { [weak self] queryRes in
print("onNext called!")
},
onCompleted: { [weak self] in
print("onCompleted called!")
}
)
.disposed(by: self.disposeBag)
and my ajaxLoad method:
func ajaxLoad(var1 myVar: String) -> Observable<QueryResponse> {
return Observable.create { observable in
apollo.fetch(query: MyQuery()) { (result, _) in
observable.onNext(result?.data?.myQuery)
observable.onCompleted()
}
return Disposables.create()
}
}
I'm fairly new to ReactiveX so I may be a little hazy on what the Rx lifecycle actually looks like. Why might onNext be called in the flatMapLatest call, but not onCompleted? Any help would be appreciated. Thanks in advance!
The flatMap operator does not emit completed events of any observable that you return inside the block.
The following code illustrates this clearly. .just(_) emits the element and then a completed event, which does not terminate to subscription.
_ = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.debug("before flatmap")
.flatMap { .just($0 * 2) }
.debug("after flatmap")
.subscribe()
In fact, Variable only emits completed when deallocated. See source v4.0.
Note that Variable is deprecated in RxSwift 4, you are encouraged to use RxCocoa's similar BehaviorRelay instead.
deinit {
_subject.on(.completed)
}
Since you said you are new and a "little hazy"...
Keep in mind that whenever localVar changes, it emits a new value and ajaxLoad(var1:) gets called. The result of ajaxLoad(var1:) then gets pushed to your subscribe's onNext closure.
Also keep in mind that if an Observable emits a .completed it's dead. It can no longer emit anything else.
So flatMapLatest can't complete (unless its source completes.) If it did, it would kill the whole pipe and no more changes to localVar would get routed through the pipe, ajaxLoad(var:1) wouldn't get called again with the new value and nothing more would get pushed to the subscribe's onNext method.
A sequence of observables can be thought of like a Rube Goldberg machine where a completed shuts down the machine and an error breaks it. The only time you should shut down the machine is if the source (in this case localVar) is finished emitting values or the sink (destination, in this case the onNext: closure) doesn't want any more values.

ReactiveX RxSwift get first non error from concat of observables

I am using RxSwift for caching in my iOS app and have a piece of code like this:
let observable = Observable.of(cache.getItem(itemID), network.getItem(itemID)).concat().take(1)
observable.subscribeNext // and do some stuff
I have the cache.getItem method doing an onError if it has no value, and would like it to then defer to the network, but for some reason the network is never run. I assume its because I am using the take(1), but I would like the observable to stop emitting once the cache finds something (or continue to the network if it does not).
Any ideas on how to do this?
I've been following this guide but he does not go into detail about his cache's behavior when it fails to find something.
You shouldn't be using .Error like that. That's not really conceptually an error case. There's just nothing in the cache. That's a common situation. Nothing went "wrong" out of the ordinary. Instead, just send a .Completed event.
As for why your code isn't working, it's because an error coming from an Observable included in the concat will become an error on the final concat Observable. The thing to remember with Rx is that once there's a .Completed event or (in your case) an .Error event, that's it, it's over, no more .Next events (or any events).
So instead, if you use .Completed, your code would work as so:
class Cache {
func getItem(itemID: Int) -> Observable<Item> {
return Observable<Item>.create { observer in
// if not found...
observer.onCompleted() // you would of course really try to get it
// from the cache first.
return NopDisposable.instance
}
}
}
class Network {
func getItemN(itemID: Int) -> Observable<Item> {
return Observable<Item>.create { observer in
// get some `item` from the network and then..
observer.onNext(item)
return NopDisposable.instance
}
}
}
let observable = Observable.of(cache.getItem(itemID), network.getItem(itemID)).concat().take(1)
observable.subscribeNext { item in
print(item)
}

Proper way to dispose a one-off observable in RxSwift

I have an observable that I only want to kick off once. The docs say:
Using dispose bags or takeUntil operator is a robust way of making sure resources are cleaned up. We recommend using them in production even if the sequences will terminate in finite time.
My observable terminates after just one event
let observable = Observable.create() { observer in
webservice.makeHTTPRequestWithCompletionBlock {
if something {
observer.on(.Next(...))
observer.onCompleted()
} else {
observer.on(.Error(...))
}
}
}
Say I wasn't interested in cancelling subscribers to this observable, I just want it run once and complete. I want the lifecycle of this observable to end when the work itself is completed. Meaning there are no good candidates for disposeBag that I can see. takeUntil also expects an 'event', and there are no good ones that I can see.
Right now I just solve the warning by throwing away the disposable:
_ = observeable.subscribeNext { ... }
Is there a way to do this, or a different paradigm that I should use?
Both DiposeBag and takeUntil are used to cancel a subscription prior to receiving the .Completed/.Error event.
When an Observable completes, all the resources used to manage subscription are disposed of automatically.
As of RxSwift 2.2, You can witness an example of implementation for this behavior in AnonymousObservable.swift
func on(event: Event<E>) {
switch event {
case .Next:
if _isStopped == 1 {
return
}
forwardOn(event)
case .Error, .Completed:
if AtomicCompareAndSwap(0, 1, &_isStopped) {
forwardOn(event)
dispose()
}
}
}
See how AnonymousObservableSink calls dispose on itself when receiving either an .Error or a .Completed event, after forwarding the event.
In conclusion, for this use case, _ = is the way to go.

Error Handling - Async Call

I am creating a framework for web services used in my project. I have uploaded template in GitHub. https://github.com/vivinjeganathan/ErrorHandling
It has various layers. Layer 1 for validation. Layer 2 for formation of request. Layer 3 for the actual network call.
View Controller <----> Layer 1 <---> Layer 2 <---> Layer 3
Data flows between layers through closures, if error happens at any layer it needs to be gracefully passed to the ViewController.
I have referred to this link for error handling in async calls - http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/
Created a branch in the same repo - name - ErrorHandling-Method1.
I was able to transfer error from layer 3 to layer 2(Single Level - Returning response through functions in closures - as mentioned in the link). But face difficulties in transferring back across multi layers.
Can anyone assist with the sample application provided in public GitHub?
First of all, I don't think it's necessary to stack the layers the way you did, for example, by adding the validation functionality as a layer you are increasing coupling making that layer dependant of the layers below (parsing, networking, etc.), instead, why don't you separate validation to make it only dependant of the data?:
class ViewController: UIViewController {
var validator = InputValidator()
override func viewDidLoad() {
super.viewDidLoad()
do {
try validator.validateInput("INPUT")
try Fetcher.requestDataWithParams("INPUT")
}
catch {
handleError(error)
}
}
}
Now the validation functionality is not dependant of the other layers, so communication would flow like this:
View Controller <---> ParsingLayer <---> NetworkingLayer
I did rename the layers but they are not necessarily have to be like this, you can add or remove layers.
I think is going to be kind of complicated if I try to explain my approach, so I'm going to give an example using the previous layers, first the bottom layer:
class NetworkingLayer {
class func requestData(params: AnyObject, completion: (getResult: () throw -> AnyObject) -> Void) -> Void {
session.dataTaskWithURL(url) { (data, urlResponse, var error) in
if let error = error {
completion(getResult: { throw error })
} else {
completion(getResult: { return data })
}
}
}
}
I have omitted some sections of code, but the idea is to do any necessary step to make the layer work (create session, etc.) and to always communicate back through the completion closure; a layer on top would look like this:
class ParsingLayer {
class func requestObject(params: AnyObject, completion: (getObject: () throw -> CustomObject) -> Void) -> Void {
NetworkingLayer.requestData(params, completion: { (getResult) -> Void in
do {
let data = try getResult()
let object = try self.parseData(data)
completion(getObject: { return object })
}
catch {
completion(getObject: { throw error })
}
})
}
}
Notice that the completion closures are not the same, since every layer adds functionality, the returned object can change, also notice that the code inside the do statement can fail in two ways, first if the network call fails and then if the data from the networking layer cannot be parsed; again the communication to the layer on top is always done through the completion closure.
Finally the ViewController can call the next layer using the closure expected by the Parsing layer in this case, and is able to handle errors originated in any layer:
override func viewDidLoad() {
super.viewDidLoad()
do {
try validator.validateInput("INPUT")
try ParsingLayer.requestObject("INPUT", completion: { (getObject) in
do {
let object = try getObject()
try self.validator.validateOutput(object)
print(object)
}
catch {
self.handleError(error)
}
})
catch {
handleError(error)
}
}
Notice that there is a do catch inside the completion closure, this is necessary since the call is made asynchronously, now that the response has gone through all the layers and have actually change to be of a more specialised type you can even validate the result without having the necessity to make a layer for the validation functionality.
Hope it helps.
Personally I would use notifications passing the NSError as the object of the notification in the layers and observe the notification in the view controller.
In the layers:
NSNotificationCenter.defaultCenter().postNotificationName("ErrorEncounteredNotification", object: error)
In the view controller
NSNotificationCenter.defaultCenter().addObserver(self, selector: "errorEncountered:", name: "ErrorEncounteredNotification", object: nil)
the selector method:
func errorEncountered(notification: NSNotification!) {
let error: NSError! = notification.object as! NSError
NSLog("error: \(error)")
}
You correctly identified a nasty problem with error handling in asynchronous code.
It seems to be easy with synchronous functions - which just return an error code, or have an extra error parameter, or use the new Swift throws syntax. Here is an synchronous function:
func computeSome() throws -> Some
And this is a viable function signature for an asynchronous function:
func computeSomeAsync(completion: (Some?, NSError?) -> ())
The asynchronous function returns Void and does not throw. If it fails, it calls its completion function with the error parameter set.
However, completion handlers become quickly cumbersome, especially in nested code.
The solution is to use a Future:
func computeSomeAsync() -> Future<Some>
This function is asynchronous and does not throw - and returns a Future. So, what's a future?
Well a future represents the eventual result of an asynchronous function. When you call the asynchronous function, it immediately returns and you get a placeholder for the result. This, called a future, will be eventually completed by the underlying background task that computes the value.
When the underlying task eventually succeeded, this future contains the computed value of the function. When it failed it will contain the error.
Depending on the actual implementation and the API of a Future Library, you can obtain the result by registering continuations:
let future = computeSomeAsync()
future.onSuccess { value in
print("Value: \(value)")
}
future.onFailure { error in
print("Error: \(error)")
}
It may look weird at first, but you can do awesome things with futures:
fetchUser(id).flatMap { user in
fetchProfileImage(user.profileImageUrl).flatMap { image in
cacheImage(image)
}
}
.onFailure { error in
print("Something went wrong: \(error)")
}
The above statement is asynchronous - as well as function fetchUser, fetchProfileImage and cacheImage. Error handling included.
Why declare your method throws if you never throw or even try to catch? You could throw the errors using the throwable declaration through all the layers, and even change the throwable type at each level.
UPDATE: Didnt think of throwing dont work in async operations. Using NSNotification is one good route, or you could take a look at RXSwift or similar to solve it too. My personal recommendation would be to use RxSwift. This keeps you out of callback hell, which you are currently travelling down into.

Resources