You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
4.5 KiB
107 lines
4.5 KiB
// |
|
// 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 |
|
|
|
|