123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- //
- // RACKVOChannel.h
- // ReactiveObjC
- //
- // Created by Uri Baghin on 27/12/2012.
- // Copyright (c) 2012 GitHub, Inc. All rights reserved.
- //
- #import "RACChannel.h"
- #import <ReactiveObjC/RACEXTKeyPathCoding.h>
- #import "RACmetamacros.h"
- /// Creates a RACKVOChannel to the given key path. When the targeted object
- /// deallocates, the channel will complete.
- ///
- /// If RACChannelTo() is used as an expression, it returns a RACChannelTerminal that
- /// can be used to watch the specified property for changes, and set new values
- /// for it. The terminal will start with the property's current value upon
- /// subscription.
- ///
- /// If RACChannelTo() is used on the left-hand side of an assignment, there must a
- /// RACChannelTerminal on the right-hand side of the assignment. The two will be
- /// subscribed to one another: the property's value is immediately set to the
- /// value of the channel terminal on the right-hand side, and subsequent changes
- /// to either terminal will be reflected on the other.
- ///
- /// There are two different versions of this macro:
- ///
- /// - RACChannelTo(TARGET, KEYPATH, NILVALUE) will create a channel to the `KEYPATH`
- /// of `TARGET`. If the terminal is ever sent a `nil` value, the property will
- /// be set to `NILVALUE` instead. `NILVALUE` may itself be `nil` for object
- /// properties, but an NSValue should be used for primitive properties, to
- /// avoid an exception if `nil` is sent (which might occur if an intermediate
- /// object is set to `nil`).
- /// - RACChannelTo(TARGET, KEYPATH) is the same as the above, but `NILVALUE` defaults to
- /// `nil`.
- ///
- /// Examples
- ///
- /// RACChannelTerminal *integerChannel = RACChannelTo(self, integerProperty, @42);
- ///
- /// // Sets self.integerProperty to 5.
- /// [integerChannel sendNext:@5];
- ///
- /// // Logs the current value of self.integerProperty, and all future changes.
- /// [integerChannel subscribeNext:^(id value) {
- /// NSLog(@"value: %@", value);
- /// }];
- ///
- /// // Binds properties to each other, taking the initial value from the right
- /// side.
- /// RACChannelTo(view, objectProperty) = RACChannelTo(model, objectProperty);
- /// RACChannelTo(view, integerProperty, @2) = RACChannelTo(model, integerProperty, @10);
- #define RACChannelTo(TARGET, ...) \
- metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
- (RACChannelTo_(TARGET, __VA_ARGS__, nil)) \
- (RACChannelTo_(TARGET, __VA_ARGS__))
- /// Do not use this directly. Use the RACChannelTo macro above.
- #define RACChannelTo_(TARGET, KEYPATH, NILVALUE) \
- [[RACKVOChannel alloc] initWithTarget:(TARGET) keyPath:@keypath(TARGET, KEYPATH) nilValue:(NILVALUE)][@keypath(RACKVOChannel.new, followingTerminal)]
- NS_ASSUME_NONNULL_BEGIN
- /// A RACChannel that observes a KVO-compliant key path for changes.
- @interface RACKVOChannel<ValueType> : RACChannel<ValueType>
- /// Initializes a channel that will observe the given object and key path.
- ///
- /// The current value of the key path, and future KVO notifications for the given
- /// key path, will be sent to subscribers of the channel's `followingTerminal`.
- /// Values sent to the `followingTerminal` will be set at the given key path using
- /// key-value coding.
- ///
- /// When the target object deallocates, the channel will complete. Signal errors
- /// are considered undefined behavior.
- ///
- /// This is the designated initializer for this class.
- ///
- /// target - The object to bind to.
- /// keyPath - The key path to observe and set the value of.
- /// nilValue - The value to set at the key path whenever a `nil` value is
- /// received. This may be nil when connecting to object properties, but
- /// an NSValue should be used for primitive properties, to avoid an
- /// exception if `nil` is received (which might occur if an intermediate
- /// object is set to `nil`).
- #if OS_OBJECT_HAVE_OBJC_SUPPORT
- - (instancetype)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(nullable ValueType)nilValue;
- #else
- // Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :(
- - (instancetype)initWithTarget:(NSObject *)target keyPath:(NSString *)keyPath nilValue:(nullable ValueType)nilValue;
- #endif
- - (instancetype)init __attribute__((unavailable("Use -initWithTarget:keyPath:nilValue: instead")));
- @end
- /// Methods needed for the convenience macro. Do not call explicitly.
- @interface RACKVOChannel (RACChannelTo)
- - (RACChannelTerminal *)objectForKeyedSubscript:(NSString *)key;
- - (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key;
- @end
- NS_ASSUME_NONNULL_END
|