RACSequence.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //
  2. // RACSequence.h
  3. // ReactiveCocoa
  4. //
  5. // Created by Justin Spahr-Summers on 2012-10-29.
  6. // Copyright (c) 2012 GitHub. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. #import "RACStream.h"
  10. @class RACScheduler;
  11. @class RACSignal;
  12. /// Represents an immutable sequence of values. Unless otherwise specified, the
  13. /// sequences' values are evaluated lazily on demand. Like Cocoa collections,
  14. /// sequences cannot contain nil.
  15. ///
  16. /// Most inherited RACStream methods that accept a block will execute the block
  17. /// _at most_ once for each value that is evaluated in the returned sequence.
  18. /// Side effects are subject to the behavior described in
  19. /// +sequenceWithHeadBlock:tailBlock:.
  20. ///
  21. /// Implemented as a class cluster. A minimal implementation for a subclass
  22. /// consists simply of -head and -tail.
  23. @interface RACSequence : RACStream <NSCoding, NSCopying, NSFastEnumeration>
  24. /// The first object in the sequence, or nil if the sequence is empty.
  25. ///
  26. /// Subclasses must provide an implementation of this method.
  27. @property (nonatomic, strong, readonly) id head;
  28. /// All but the first object in the sequence, or nil if there are no other
  29. /// objects.
  30. ///
  31. /// Subclasses must provide an implementation of this method.
  32. @property (nonatomic, strong, readonly) RACSequence *tail;
  33. /// Evaluates the full sequence to produce an equivalently-sized array.
  34. @property (nonatomic, copy, readonly) NSArray *array;
  35. /// Returns an enumerator of all objects in the sequence.
  36. @property (nonatomic, copy, readonly) NSEnumerator *objectEnumerator;
  37. /// Converts a sequence into an eager sequence.
  38. ///
  39. /// An eager sequence fully evaluates all of its values immediately. Sequences
  40. /// derived from an eager sequence will also be eager.
  41. ///
  42. /// Returns a new eager sequence, or the receiver if the sequence is already
  43. /// eager.
  44. @property (nonatomic, copy, readonly) RACSequence *eagerSequence;
  45. /// Converts a sequence into a lazy sequence.
  46. ///
  47. /// A lazy sequence evaluates its values on demand, as they are accessed.
  48. /// Sequences derived from a lazy sequence will also be lazy.
  49. ///
  50. /// Returns a new lazy sequence, or the receiver if the sequence is already lazy.
  51. @property (nonatomic, copy, readonly) RACSequence *lazySequence;
  52. /// Invokes -signalWithScheduler: with a new RACScheduler.
  53. - (RACSignal *)signal;
  54. /// Evaluates the full sequence on the given scheduler.
  55. ///
  56. /// Each item is evaluated in its own scheduled block, such that control of the
  57. /// scheduler is yielded between each value.
  58. ///
  59. /// Returns a signal which sends the receiver's values on the given scheduler as
  60. /// they're evaluated.
  61. - (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler;
  62. /// Applies a left fold to the sequence.
  63. ///
  64. /// This is the same as iterating the sequence along with a provided start value.
  65. /// This uses a constant amount of memory. A left fold is left-associative so in
  66. /// the sequence [1,2,3] the block would applied in the following order:
  67. /// reduce(reduce(reduce(start, 1), 2), 3)
  68. ///
  69. /// start - The starting value for the fold. Used as `accumulator` for the
  70. /// first fold.
  71. /// reduce - The block used to combine the accumulated value and the next value.
  72. /// Cannot be nil.
  73. ///
  74. /// Returns a reduced value.
  75. - (id)foldLeftWithStart:(id)start reduce:(id (^)(id accumulator, id value))reduce;
  76. /// Applies a right fold to the sequence.
  77. ///
  78. /// A right fold is equivalent to recursion on the list. The block is evaluated
  79. /// from the right to the left in list. It is right associative so it's applied
  80. /// to the rightmost elements first. For example, in the sequence [1,2,3] the
  81. /// block is applied in the order:
  82. /// reduce(1, reduce(2, reduce(3, start)))
  83. ///
  84. /// start - The starting value for the fold.
  85. /// reduce - The block used to combine the accumulated value and the next head.
  86. /// The block is given the accumulated value and the value of the rest
  87. /// of the computation (result of the recursion). This is computed when
  88. /// you retrieve its value using `rest.head`. This allows you to
  89. /// prevent unnecessary computation by not accessing `rest.head` if you
  90. /// don't need to.
  91. ///
  92. /// Returns a reduced value.
  93. - (id)foldRightWithStart:(id)start reduce:(id (^)(id first, RACSequence *rest))reduce;
  94. /// Check if any value in sequence passes the block.
  95. ///
  96. /// block - The block predicate used to check each item. Cannot be nil.
  97. ///
  98. /// Returns a boolean indiciating if any value in the sequence passed.
  99. - (BOOL)any:(BOOL (^)(id value))block;
  100. /// Check if all values in the sequence pass the block.
  101. ///
  102. /// block - The block predicate used to check each item. Cannot be nil.
  103. ///
  104. /// Returns a boolean indicating if all values in the sequence passed.
  105. - (BOOL)all:(BOOL (^)(id value))block;
  106. /// Returns the first object that passes the block.
  107. ///
  108. /// block - The block predicate used to check each item. Cannot be nil.
  109. ///
  110. /// Returns an object that passes the block or nil if no objects passed.
  111. - (id)objectPassingTest:(BOOL (^)(id value))block;
  112. /// Creates a sequence that dynamically generates its values.
  113. ///
  114. /// headBlock - Invoked the first time -head is accessed.
  115. /// tailBlock - Invoked the first time -tail is accessed.
  116. ///
  117. /// The results from each block are memoized, so each block will be invoked at
  118. /// most once, no matter how many times the head and tail properties of the
  119. /// sequence are accessed.
  120. ///
  121. /// Any side effects in `headBlock` or `tailBlock` should be thread-safe, since
  122. /// the sequence may be evaluated at any time from any thread. Not only that, but
  123. /// -tail may be accessed before -head, or both may be accessed simultaneously.
  124. /// As noted above, side effects will only be triggered the _first_ time -head or
  125. /// -tail is invoked.
  126. ///
  127. /// Returns a sequence that lazily invokes the given blocks to provide head and
  128. /// tail. `headBlock` must not be nil.
  129. + (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock;
  130. @end
  131. @interface RACSequence (Unavailable)
  132. - (id)foldLeftWithStart:(id)start combine:(id (^)(id accumulator, id value))combine __attribute__((unavailable("Renamed to -foldLeftWithStart:reduce:")));
  133. - (id)foldRightWithStart:(id)start combine:(id (^)(id first, RACSequence *rest))combine __attribute__((unavailable("Renamed to -foldRightWithStart:reduce:")));
  134. @end