forked from Lightricks/ReactiveObjC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNSObject+RACPropertySubscribing.h
120 lines (106 loc) · 4.71 KB
/
NSObject+RACPropertySubscribing.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
// NSObject+RACPropertySubscribing.h
// ReactiveObjC
//
// Created by Josh Abernathy on 3/2/12.
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <ReactiveObjC/EXTKeyPathCoding.h>
#import <ReactiveObjC/metamacros.h>
/// Creates a signal which observes `KEYPATH` on `TARGET` for changes.
///
/// In either case, the observation continues until `TARGET` _or self_ is
/// deallocated. If any intermediate object is deallocated instead, it will be
/// assumed to have been set to nil.
///
/// Make sure to `@rac_strongify(self)` when using this macro within a block! The
/// macro will _always_ reference `self`, which can silently introduce a retain
/// cycle within a block. As a result, you should make sure that `self` is a weak
/// reference (e.g., created by `@rac_weakify` and `@rac_strongify`) before the
/// expression that uses `RACObserve`.
///
/// Examples
///
/// // Observes self, and doesn't stop until self is deallocated.
/// RACSignal *selfSignal = RACObserve(self, arrayController.items);
///
/// // Observes the array controller, and stops when self _or_ the array
/// // controller is deallocated.
/// RACSignal *arrayControllerSignal = RACObserve(self.arrayController, items);
///
/// // Observes obj.arrayController, and stops when self _or_ the array
/// // controller is deallocated.
/// RACSignal *signal2 = RACObserve(obj.arrayController, items);
///
/// @rac_weakify(self);
/// RACSignal *signal3 = [anotherSignal flattenMap:^(NSArrayController *arrayController) {
/// // Avoids a retain cycle because of RACObserve implicitly referencing
/// // self.
/// @rac_strongify(self);
/// return RACObserve(arrayController, items);
/// }];
///
/// Returns a signal which sends the current value of the key path on
/// subscription, then sends the new value every time it changes, and sends
/// completed if self or observer is deallocated.
#define _RACObserve(TARGET, KEYPATH) \
({ \
__weak id target_ = (TARGET); \
[target_ rac_valuesForKeyPath:@rac_keypath(TARGET, KEYPATH) observer:self]; \
})
#if __clang__ && (__clang_major__ >= 8)
#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)
#else
#define RACObserve(TARGET, KEYPATH) \
({ \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wreceiver-is-weak\"") \
_RACObserve(TARGET, KEYPATH) \
_Pragma("clang diagnostic pop") \
})
#endif
@class RACDisposable;
@class RACTwoTuple<__covariant First, __covariant Second>;
@class RACSignal<__covariant ValueType>;
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (RACPropertySubscribing)
/// Creates a signal to observe the value at the given key path.
///
/// The initial value is sent on subscription, the subsequent values are sent
/// from whichever thread the change occured on, even if it doesn't have a valid
/// scheduler.
///
/// Returns a signal that immediately sends the receiver's current value at the
/// given keypath, then any changes thereafter.
#if OS_OBJECT_HAVE_OBJC_SUPPORT
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;
#else
// Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :(
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(NSObject *)observer;
#endif
/// Creates a signal to observe the changes of the given key path.
///
/// The initial value is sent on subscription if `NSKeyValueObservingOptionInitial` is set.
/// The subsequent values are sent from whichever thread the change occured on,
/// even if it doesn't have a valid scheduler.
///
/// Returns a signal that sends tuples containing the current value at the key
/// path and the change dictionary for each KVO callback.
#if OS_OBJECT_HAVE_OBJC_SUPPORT
- (RACSignal<RACTwoTuple<id, NSDictionary *> *> *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer;
#else
- (RACSignal<RACTwoTuple<id, NSDictionary *> *> *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(NSObject *)observer;
#endif
@end
NS_ASSUME_NONNULL_END
#define RACAble(...) \
rac_metamacro_if_eq(1, rac_metamacro_argcount(__VA_ARGS__)) \
(_RACAbleObject(self, __VA_ARGS__)) \
(_RACAbleObject(__VA_ARGS__))
#define _RACAbleObject(object, property) [object rac_signalForKeyPath:@rac_keypath(object, property) observer:self]
#define RACAbleWithStart(...) \
rac_metamacro_if_eq(1, rac_metamacro_argcount(__VA_ARGS__)) \
(_RACAbleWithStartObject(self, __VA_ARGS__)) \
(_RACAbleWithStartObject(__VA_ARGS__))
#define _RACAbleWithStartObject(object, property) [object rac_signalWithStartingValueForKeyPath:@rac_keypath(object, property) observer:self]