| // |
| // RACSignal.h |
| // ReactiveCocoa |
| // |
| // Created by Josh Abernathy on 3/1/12. |
| // Copyright (c) 2012 GitHub, Inc. All rights reserved. |
| // |
| |
| #import <Foundation/Foundation.h> |
| #import "RACStream.h" |
| |
| @class RACDisposable; |
| @class RACScheduler; |
| @class RACSubject; |
| @protocol RACSubscriber; |
| |
| @interface RACSignal : RACStream |
| |
| /// Creates a new signal. This is the preferred way to create a new signal |
| /// operation or behavior. |
| /// |
| /// Events can be sent to new subscribers immediately in the `didSubscribe` |
| /// block, but the subscriber will not be able to dispose of the signal until |
| /// a RACDisposable is returned from `didSubscribe`. In the case of infinite |
| /// signals, this won't _ever_ happen if events are sent immediately. |
| /// |
| /// To ensure that the signal is disposable, events can be scheduled on the |
| /// +[RACScheduler currentScheduler] (so that they're deferred, not sent |
| /// immediately), or they can be sent in the background. The RACDisposable |
| /// returned by the `didSubscribe` block should cancel any such scheduling or |
| /// asynchronous work. |
| /// |
| /// didSubscribe - Called when the signal is subscribed to. The new subscriber is |
| /// passed in. You can then manually control the <RACSubscriber> by |
| /// sending it -sendNext:, -sendError:, and -sendCompleted, |
| /// as defined by the operation you're implementing. This block |
| /// should return a RACDisposable which cancels any ongoing work |
| /// triggered by the subscription, and cleans up any resources or |
| /// disposables created as part of it. When the disposable is |
| /// disposed of, the signal must not send any more events to the |
| /// `subscriber`. If no cleanup is necessary, return nil. |
| /// |
| /// **Note:** The `didSubscribe` block is called every time a new subscriber |
| /// subscribes. Any side effects within the block will thus execute once for each |
| /// subscription, not necessarily on one thread, and possibly even |
| /// simultaneously! |
| + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe; |
| |
| /// Returns a signal that immediately sends the given error. |
| + (RACSignal *)error:(NSError *)error; |
| |
| /// Returns a signal that never completes. |
| + (RACSignal *)never; |
| |
| /// Immediately schedules the given block on the given scheduler. The block is |
| /// given a subscriber to which it can send events. |
| /// |
| /// scheduler - The scheduler on which `block` will be scheduled and results |
| /// delivered. Cannot be nil. |
| /// block - The block to invoke. Cannot be NULL. |
| /// |
| /// Returns a signal which will send all events sent on the subscriber given to |
| /// `block`. All events will be sent on `scheduler` and it will replay any missed |
| /// events to new subscribers. |
| + (RACSignal *)startEagerlyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id<RACSubscriber> subscriber))block; |
| |
| /// Invokes the given block only on the first subscription. The block is given a |
| /// subscriber to which it can send events. |
| /// |
| /// Note that disposing of the subscription to the returned signal will *not* |
| /// dispose of the underlying subscription. If you need that behavior, see |
| /// -[RACMulticastConnection autoconnect]. The underlying subscription will never |
| /// be disposed of. Because of this, `block` should never return an infinite |
| /// signal since there would be no way of ending it. |
| /// |
| /// scheduler - The scheduler on which the block should be scheduled. Note that |
| /// if given +[RACScheduler immediateScheduler], the block will be |
| /// invoked synchronously on the first subscription. Cannot be nil. |
| /// block - The block to invoke on the first subscription. Cannot be NULL. |
| /// |
| /// Returns a signal which will pass through the events sent to the subscriber |
| /// given to `block` and replay any missed events to new subscribers. |
| + (RACSignal *)startLazilyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id<RACSubscriber> subscriber))block; |
| |
| @end |
| |
| @interface RACSignal (RACStream) |
| |
| /// Returns a signal that immediately sends the given value and then completes. |
| + (RACSignal *)return:(id)value; |
| |
| /// Returns a signal that immediately completes. |
| + (RACSignal *)empty; |
| |
| /// Subscribes to `signal` when the source signal completes. |
| - (RACSignal *)concat:(RACSignal *)signal; |
| |
| /// Zips the values in the receiver with those of the given signal to create |
| /// RACTuples. |
| /// |
| /// The first `next` of each stream will be combined, then the second `next`, and |
| /// so forth, until either signal completes or errors. |
| /// |
| /// signal - The signal to zip with. This must not be `nil`. |
| /// |
| /// Returns a new signal of RACTuples, representing the combined values of the |
| /// two signals. Any error from one of the original signals will be forwarded on |
| /// the returned signal. |
| - (RACSignal *)zipWith:(RACSignal *)signal; |
| |
| @end |
| |
| @interface RACSignal (Subscription) |
| |
| /// Subscribes `subscriber` to changes on the receiver. The receiver defines which |
| /// events it actually sends and in what situations the events are sent. |
| /// |
| /// Subscription will always happen on a valid RACScheduler. If the |
| /// +[RACScheduler currentScheduler] cannot be determined at the time of |
| /// subscription (e.g., because the calling code is running on a GCD queue or |
| /// NSOperationQueue), subscription will occur on a private background scheduler. |
| /// On the main thread, subscriptions will always occur immediately, with a |
| /// +[RACScheduler currentScheduler] of +[RACScheduler mainThreadScheduler]. |
| /// |
| /// This method must be overridden by any subclasses. |
| /// |
| /// Returns nil or a disposable. You can call -[RACDisposable dispose] if you |
| /// need to end your subscription before it would "naturally" end, either by |
| /// completing or erroring. Once the disposable has been disposed, the subscriber |
| /// won't receive any more events from the subscription. |
| - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber; |
| |
| /// Convenience method to subscribe to the `next` event. |
| /// |
| /// This corresponds to `IObserver<T>.OnNext` in Rx. |
| - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock; |
| |
| /// Convenience method to subscribe to the `next` and `completed` events. |
| - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock; |
| |
| /// Convenience method to subscribe to the `next`, `completed`, and `error` events. |
| - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock; |
| |
| /// Convenience method to subscribe to `error` events. |
| /// |
| /// This corresponds to the `IObserver<T>.OnError` in Rx. |
| - (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock; |
| |
| /// Convenience method to subscribe to `completed` events. |
| /// |
| /// This corresponds to the `IObserver<T>.OnCompleted` in Rx. |
| - (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock; |
| |
| /// Convenience method to subscribe to `next` and `error` events. |
| - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock; |
| |
| /// Convenience method to subscribe to `error` and `completed` events. |
| - (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock; |
| |
| @end |
| |
| /// Additional methods to assist with debugging. |
| @interface RACSignal (Debugging) |
| |
| /// Logs all events that the receiver sends. |
| - (RACSignal *)logAll; |
| |
| /// Logs each `next` that the receiver sends. |
| - (RACSignal *)logNext; |
| |
| /// Logs any error that the receiver sends. |
| - (RACSignal *)logError; |
| |
| /// Logs any `completed` event that the receiver sends. |
| - (RACSignal *)logCompleted; |
| |
| @end |
| |
| /// Additional methods to assist with unit testing. |
| /// |
| /// **These methods should never ship in production code.** |
| @interface RACSignal (Testing) |
| |
| /// Spins the main run loop for a short while, waiting for the receiver to send a `next`. |
| /// |
| /// **Because this method executes the run loop recursively, it should only be used |
| /// on the main thread, and only from a unit test.** |
| /// |
| /// defaultValue - Returned if the receiver completes or errors before sending |
| /// a `next`, or if the method times out. This argument may be |
| /// nil. |
| /// success - If not NULL, set to whether the receiver completed |
| /// successfully. |
| /// error - If not NULL, set to any error that occurred. |
| /// |
| /// Returns the first value received, or `defaultValue` if no value is received |
| /// before the signal finishes or the method times out. |
| - (id)asynchronousFirstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error; |
| |
| /// Spins the main run loop for a short while, waiting for the receiver to complete. |
| /// |
| /// **Because this method executes the run loop recursively, it should only be used |
| /// on the main thread, and only from a unit test.** |
| /// |
| /// error - If not NULL, set to any error that occurs. |
| /// |
| /// Returns whether the signal completed successfully before timing out. If NO, |
| /// `error` will be set to any error that occurred. |
| - (BOOL)asynchronouslyWaitUntilCompleted:(NSError **)error; |
| |
| @end |
| |
| @interface RACSignal (Deprecated) |
| |
| + (RACSignal *)start:(id (^)(BOOL *success, NSError **error))block __attribute__((deprecated("Use +startEagerlyWithScheduler:block: instead"))); |
| + (RACSignal *)startWithScheduler:(RACScheduler *)scheduler subjectBlock:(void (^)(RACSubject *subject))block __attribute__((deprecated("Use +startEagerlyWithScheduler:block: instead"))); |
| + (RACSignal *)startWithScheduler:(RACScheduler *)scheduler block:(id (^)(BOOL *success, NSError **error))block __attribute__((deprecated("Use +startEagerlyWithScheduler:block: instead"))); |
| |
| @end |