// // RACSignal.h // ReactiveCocoa // // Created by Josh Abernathy on 3/1/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #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 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 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 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 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)subscriber; /// Convenience method to subscribe to the `next` event. /// /// This corresponds to `IObserver.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.OnError` in Rx. - (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock; /// Convenience method to subscribe to `completed` events. /// /// This corresponds to the `IObserver.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