Breaking from a tradition of covering Apple APIs exclusively, this edition of NSHipster will look at an open source project that exemplifies this brave new era for Objective-C.
他认为 ReactiveCocoa 打破了苹果 API 排他性的束缚,勇敢地开创了 Objective-C 的新纪元,具有划时代的意义。不得不说,这对于一个第三方框架来说,已经是非常高的评价了。
/// An abstract class representing any stream of values.////// This class represents a monad, upon which many stream-based operations can/// be built.////// When subclassing RACStream, only the methods in the main @interface body need/// to be overridden.
@interface RACStream : NSObject
/// Lifts `value` into the stream monad.////// Returns a stream containing only the given value.
+ (instancetype)return:(id)value;
/// Lazily binds a block to the values in the receiver.////// This should only be used if you need to terminate the bind early, or close/// over some state. -flattenMap: is more appropriate for all other cases.////// block - A block returning a RACStreamBindBlock. This block will be invoked/// each time the bound stream is re-evaluated. This block must not be/// nil or return nil.////// Returns a new stream which represents the combined result of all lazy/// applications of `block`.
- (instancetype)bind:(RACStreamBindBlock (^)(void))block;
@end
事实上,一个序列的 tail 仍然是一个序列,如果我们将序列看作是一条毛毛虫,那么 head 和 tail 可表示如下:
同样的,一个序列的 tail 也可以看作是由 head 和 tail 组成,而这个新的 tail 又可以继续看作是由 head 和 tail 组成,这个过程可以一直进行下去。而这个就是 RACSequence 得以建立的理论基础,所以一个 RACSequence 子类的最小实现就是 head 和 tail :
/// Represents an immutable sequence of values. Unless otherwise specified, the/// sequences' values are evaluated lazily on demand. Like Cocoa collections,/// sequences cannot contain nil.////// Most inherited RACStream methods that accept a block will execute the block/// _at most_ once for each value that is evaluated in the returned sequence./// Side effects are subject to the behavior described in/// +sequenceWithHeadBlock:tailBlock:.////// Implemented as a class cluster. A minimal implementation for a subclass/// consists simply of -head and -tail.
@interface RACSequence : RACStream <NSCoding, NSCopying, NSFastEnumeration>
/// The first object in the sequence, or nil if the sequence is empty.////// Subclasses must provide an implementation of this method.
@property (nonatomic, strong, readonly) id head;
/// All but the first object in the sequence, or nil if the sequence is empty.////// Subclasses must provide an implementation of this method.
@property (nonatomic, strong, readonly) RACSequence *tail;
@end
/// Represents any object which can directly receive values from a RACSignal.////// You generally shouldn't need to implement this protocol. +[RACSignal/// createSignal:], RACSignal's subscription methods, or RACSubject should work/// for most uses.////// Implementors of this protocol may receive messages and values from multiple/// threads simultaneously, and so should be thread-safe. Subscribers will also/// be weakly referenced so implementations must allow that.
@protocol RACSubscriber <NSObject>
@required
/// Sends the next value to subscribers.////// value - The value to send. This can be `nil`.
- (void)sendNext:(id)value;
/// Sends the error to subscribers.////// error - The error to send. This can be `nil`.////// This terminates the subscription, and invalidates the subscriber (such that/// it cannot subscribe to anything else in the future).
- (void)sendError:(NSError *)error;
/// Sends completed to subscribers.////// This terminates the subscription, and invalidates the subscriber (such that/// it cannot subscribe to anything else in the future).
- (void)sendCompleted;
/// Sends the subscriber a disposable that represents one of its subscriptions.////// A subscriber may receive multiple disposables if it gets subscribed to/// multiple signals; however, any error or completed events must terminate _all_/// subscriptions.
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
@end