13

I have a function that return a Bool Observable depending if it was ok or not.

func test() -> Observable<Bool> {
   if everythingIsOk {
      return just(true)
   }
   return just(false) <- how can i here return a custom error to retrieve what failed?
}
Godfather
  • 4,040
  • 6
  • 43
  • 70

3 Answers3

12
just<E>(element: E) -> Observable<E>

Returns an observable sequence that contains a single element. Instead, you should use something like that:

create<E>(subscribe: (AnyObserver<E>) -> Disposable) -> Observable<E>

Create method creates an observable sequence from a specified subscribe method implementation.

In your case:

private let realm = try! Realm()

func save(customObject: CustomObject) -> Observable<Bool> {
    return create({ observer -> Disposable in
        do {
            try self.realm.write {
                self.realm.add(customObject, update: true)
                observer.onNext(true)
                observer.onCompleted()
            }
        } catch {
            // .Error sequence will be automatically completed
            observer.onError(NSError(domai...)
        }

        // if realm.write is sync task(by default it is, as I know) you can actually return NopDisposable
        return NopDisposable.instance
        // otherwise you should cancel write transaction in AnonymousDisposable
    })
}

AnonymousDisposable is the action that’s called in case you want to get interrupted. Say you leave your view controller or the app needs to be done with the service and you don’t need to call this request any longer. It’s great for video uploads or something much larger. You can do request.cancel() which cleans up all the resources when you’re done with it. This gets called on either completion or error.

  • Just want to add that in my experience it's best to put the onNext() etc. outside of the try block. The Realm write isn't actually persisted until it exists that closure. – Morgz May 12 '16 at 17:30
4

For creating observables there is create function. You can use it like this:

func test() -> Observable<Bool> {
   return create({ (observer) -> Disposable in
//      Some condition
      observer.onNext(true)
//      Some other condition
      observer.onNext(false)
//      Some other condition
      observer.onError(NSError(domain: "My domain", code: -1, userInfo: nil))
//      Some other condition
      observer.onCompleted()

      return AnonymousDisposable {
//         Dispose resources here
      }
//      If u have nothing to dipose use NopDisposable.instance


   })
}
Serg Dort
  • 477
  • 2
  • 5
  • Whats the difference between observer.onNext(true) And just(true) – Godfather Dec 20 '15 at 22:11
  • 1
    In your simple example there is no difference, but in more complex, if for example you need to make some asynchronous work, like network request or fetch some data from data base you will not be able to do this. And just operator never fails it "just" posts the value , which you what to post – Serg Dort Dec 20 '15 at 22:38
  • I'm not sure why you put .onCompleted() in other condition, its supposed to be called always despite it completes successful or failed ? – Godfather Dec 28 '15 at 08:29
  • The meaning of `.onCompleted()` that you are done. Yeah my bad :( . Also it will call onComplete callback if it exists on subscriptions and (as well as onError) call `dispose` on `Disposable` – Serg Dort Dec 29 '15 at 08:31
2

Use a result enum as your observable value.

public enum Result<Value> {
    case success(Value)
    case failure(Error)
}

func test() -> Observable<Result<Bool>> {
   if everythingIsOk {
      return just(.success(true))
   }

   let error = ...
   return just(.failure(error))
}
  • 1
    observables should send values of the specified type, or fail. mixing the 2 is a negative pattern to observables concept because you can receive an error either in the `onNext` block and the `onError` block. – Ariel Apr 09 '17 at 12:30
  • You are correct, but there are some cases where you don't want the subscription to end because of an error. – Tommy Sadiq Hinrichsen Aug 19 '21 at 12:33
  • than you can use `materialize`/`dematerialize` or `catchError(...)`/`catchErrorJustReturn(...)`. – Ariel Jan 25 '22 at 09:38
  • catchError and catchErrorJustReturn will also send a completed event and thus ending the subscription. – Tommy Sadiq Hinrichsen Jan 25 '22 at 12:12