Skip to content

Commit 6ec5068

Browse files
committed
Redeclare operations built on RACStream primitives with more precise ValueType information
Since the operations built on RACStream primitives have an `instancetype` return value, the compiler assumes that they inherit the receiving signal’s `ValueType`. For operators like `map:`, this is almost always an incorrect assumption. As such, in cases where the `ValueType` of the result of the operation is not able to be inferred, the `ValueType` is erased in the result by returning `RACSignal *` with no `ValueType` information. Additionally, in cases where `instancetype` is a valid return type and no more precise `ValueType` information could be added to the method signature, the operation is not redeclared, since the compiler will assume the correct return type. Finally, in cases where more precise type information could be provided, the operators are redeclared as such.
1 parent e932b77 commit 6ec5068

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed

ReactiveObjC/RACSignal.h

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,210 @@ NS_ASSUME_NONNULL_BEGIN
112112

113113
@end
114114

115+
/// Redeclarations of operations built on the RACStream primitives with more
116+
/// precise ValueType information.
117+
///
118+
/// In cases where the ValueType of the result of the operation is not able to
119+
/// be inferred, the ValueType is erased in the result.
120+
///
121+
/// In cases where instancetype is a valid return type, the operation is not
122+
/// redeclared here.
123+
@interface RACSignal<__covariant ValueType> (RACStreamOperations)
124+
125+
/// Maps `block` across the values in the receiver and flattens the result.
126+
///
127+
/// Note that operators applied _after_ -flattenMap: behave differently from
128+
/// operators _within_ -flattenMap:. See the Examples section below.
129+
///
130+
/// This corresponds to the `SelectMany` method in Rx.
131+
///
132+
/// block - A block which accepts the values in the receiver and returns a new
133+
/// instance of the receiver's class. Returning `nil` from this block is
134+
/// equivalent to returning an empty signal.
135+
///
136+
/// Examples
137+
///
138+
/// [signal flattenMap:^(id x) {
139+
/// // Logs each time a returned signal completes.
140+
/// return [[RACSignal return:x] logCompleted];
141+
/// }];
142+
///
143+
/// [[signal
144+
/// flattenMap:^(id x) {
145+
/// return [RACSignal return:x];
146+
/// }]
147+
/// // Logs only once, when all of the signals complete.
148+
/// logCompleted];
149+
///
150+
/// Returns a new signal which represents the combined streams resulting from
151+
/// mapping `block`.
152+
- (RACSignal *)flattenMap:(__kindof RACStream * _Nullable (^)(ValueType _Nullable value))block;
153+
154+
/// Flattens a signal of streams.
155+
///
156+
/// This corresponds to the `Merge` method in Rx.
157+
///
158+
/// Returns a signal consisting of the combined streams obtained from the
159+
/// receiver.
160+
- (RACSignal *)flatten;
161+
162+
/// Maps `block` across the values in the receiver.
163+
///
164+
/// This corresponds to the `Select` method in Rx.
165+
///
166+
/// Returns a new signal with the mapped values.
167+
- (RACSignal *)map:(id _Nullable (^)(ValueType _Nullable value))block;
168+
169+
/// Replaces each value in the receiver with the given object.
170+
///
171+
/// Returns a new signal which includes the given object once for each value in
172+
/// the receiver.
173+
- (RACSignal *)mapReplace:(nullable id)object;
174+
175+
/// Filters out values in the receiver that don't pass the given test.
176+
///
177+
/// This corresponds to the `Where` method in Rx.
178+
///
179+
/// Returns a new signal with only those values that passed.
180+
- (RACSignal<ValueType> *)filter:(BOOL (^)(ValueType _Nullable value))block;
181+
182+
/// Filters out values in the receiver that equal (via -isEqual:) the provided
183+
/// value.
184+
///
185+
/// value - The value can be `nil`, in which case it ignores `nil` values.
186+
///
187+
/// Returns a new signal containing only the values which did not compare equal
188+
/// to `value`.
189+
- (RACSignal<ValueType> *)ignore:(nullable ValueType)value;
190+
191+
/// Unpacks each RACTuple in the receiver and maps the values to a new value.
192+
///
193+
/// reduceBlock - The block which reduces each RACTuple's values into one value.
194+
/// It must take as many arguments as the number of tuple elements
195+
/// to process. Each argument will be an object argument. The
196+
/// return value must be an object. This argument cannot be nil.
197+
///
198+
/// Returns a new signal of reduced tuple values.
199+
- (RACSignal *)reduceEach:(id _Nullable (^)())reduceBlock;
200+
201+
/// Returns a signal consisting of `value`, followed by the values in the
202+
/// receiver.
203+
- (RACSignal<ValueType> *)startWith:(nullable ValueType)value;
204+
205+
/// Skips the first `skipCount` values in the receiver.
206+
///
207+
/// Returns the receiver after skipping the first `skipCount` values. If
208+
/// `skipCount` is greater than the number of values in the signal, an empty
209+
/// signal is returned.
210+
- (RACSignal<ValueType> *)skip:(NSUInteger)skipCount;
211+
212+
/// Returns a signal of the first `count` values in the receiver. If `count` is
213+
/// greater than or equal to the number of values in the signal, a signal
214+
/// equivalent to the receiver is returned.
215+
- (RACSignal<ValueType> *)take:(NSUInteger)count;
216+
217+
/// Combines values in the receiver from left to right using the given block.
218+
///
219+
/// The algorithm proceeds as follows:
220+
///
221+
/// 1. `startingValue` is passed into the block as the `running` value, and the
222+
/// first element of the receiver is passed into the block as the `next` value.
223+
/// 2. The result of the invocation is added to the returned signal.
224+
/// 3. The result of the invocation (`running`) and the next element of the
225+
/// receiver (`next`) is passed into `block`.
226+
/// 4. Steps 2 and 3 are repeated until all values have been processed.
227+
///
228+
/// startingValue - The value to be combined with the first element of the
229+
/// receiver. This value may be `nil`.
230+
/// reduceBlock - The block that describes how to combine values of the
231+
/// receiver. If the receiver is empty, this block will never be
232+
/// invoked. Cannot be nil.
233+
///
234+
/// Examples
235+
///
236+
/// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
237+
///
238+
/// // Contains 1, 3, 6, 10
239+
/// RACSequence *sums = [numbers scanWithStart:@0 reduce:^(NSNumber *sum, NSNumber *next) {
240+
/// return @(sum.integerValue + next.integerValue);
241+
/// }];
242+
///
243+
/// Returns a new signal that consists of each application of `reduceBlock`. If
244+
/// the receiver is empty, an empty signal is returned.
245+
- (instancetype)scanWithStart:(nullable id)startingValue reduce:(id _Nullable (^)(id _Nullable running, ValueType _Nullable next))reduceBlock;
246+
247+
/// Combines values in the receiver from left to right using the given block
248+
/// which also takes zero-based index of the values.
249+
///
250+
/// startingValue - The value to be combined with the first element of the
251+
/// receiver. This value may be `nil`.
252+
/// reduceBlock - The block that describes how to combine values of the
253+
/// receiver. This block takes zero-based index value as the last
254+
/// parameter. If the receiver is empty, this block will never
255+
/// be invoked. Cannot be nil.
256+
///
257+
/// Returns a new signal that consists of each application of `reduceBlock`. If
258+
/// the receiver is empty, an empty signal is returned.
259+
- (RACSignal *)scanWithStart:(nullable id)startingValue reduceWithIndex:(id _Nullable (^)(id _Nullable running, ValueType _Nullable next, NSUInteger index))reduceBlock;
260+
261+
/// Combines each previous and current value into one object.
262+
///
263+
/// This method is similar to -scanWithStart:reduce:, but only ever operates on
264+
/// the previous and current values (instead of the whole signal), and does not
265+
/// pass the return value of `reduceBlock` into the next invocation of it.
266+
///
267+
/// start - The value passed into `reduceBlock` as `previous` for the
268+
/// first value.
269+
/// reduceBlock - The block that combines the previous value and the current
270+
/// value to create the reduced value. Cannot be nil.
271+
///
272+
/// Examples
273+
///
274+
/// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
275+
///
276+
/// // Contains 1, 3, 5, 7
277+
/// RACSequence *sums = [numbers combinePreviousWithStart:@0 reduce:^(NSNumber *previous, NSNumber *next) {
278+
/// return @(previous.integerValue + next.integerValue);
279+
/// }];
280+
///
281+
/// Returns a new signal consisting of the return values from each application of
282+
/// `reduceBlock`.
283+
- (RACSignal *)combinePreviousWithStart:(nullable ValueType)start reduce:(id _Nullable (^)(ValueType _Nullable previous, ValueType _Nullable current))reduceBlock;
284+
285+
/// Takes values until the given block returns `YES`.
286+
///
287+
/// Returns a signal of the initial values in the receiver that fail `predicate`.
288+
/// If `predicate` never returns `YES`, a signal equivalent to the receiver is
289+
/// returned.
290+
- (RACSignal<ValueType> *)takeUntilBlock:(BOOL (^)(ValueType _Nullable x))predicate;
291+
292+
/// Takes values until the given block returns `NO`.
293+
///
294+
/// Returns a signal of the initial values in the receiver that pass `predicate`.
295+
/// If `predicate` never returns `NO`, a signal equivalent to the receiver is
296+
/// returned.
297+
- (RACSignal<ValueType> *)takeWhileBlock:(BOOL (^)(ValueType _Nullable x))predicate;
298+
299+
/// Skips values until the given block returns `YES`.
300+
///
301+
/// Returns a signal containing the values of the receiver that follow any
302+
/// initial values failing `predicate`. If `predicate` never returns `YES`,
303+
/// an empty signal is returned.
304+
- (RACSignal<ValueType> *)skipUntilBlock:(BOOL (^)(ValueType _Nullable x))predicate;
305+
306+
/// Skips values until the given block returns `NO`.
307+
///
308+
/// Returns a signal containing the values of the receiver that follow any
309+
/// initial values passing `predicate`. If `predicate` never returns `NO`, an
310+
/// empty signal is returned.
311+
- (RACSignal<ValueType> *)skipWhileBlock:(BOOL (^)(ValueType _Nullable x))predicate;
312+
313+
/// Returns a signal of values for which -isEqual: returns NO when compared to the
314+
/// previous value.
315+
- (RACSignal<ValueType> *)distinctUntilChanged;
316+
317+
@end
318+
115319
@interface RACSignal<__covariant ValueType> (Subscription)
116320

117321
/// Subscribes `subscriber` to changes on the receiver. The receiver defines which

0 commit comments

Comments
 (0)