Property.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. import Foundation
  2. import enum Result.NoError
  3. /// Represents a property that allows observation of its changes.
  4. public protocol PropertyType {
  5. associatedtype Value
  6. /// The current value of the property.
  7. var value: Value { get }
  8. /// A producer for Signals that will send the property's current value,
  9. /// followed by all changes over time.
  10. var producer: SignalProducer<Value, NoError> { get }
  11. /// A signal that will send the property's changes over time.
  12. var signal: Signal<Value, NoError> { get }
  13. }
  14. /// A read-only property that allows observation of its changes.
  15. public struct AnyProperty<Value>: PropertyType {
  16. private let _value: () -> Value
  17. private let _producer: () -> SignalProducer<Value, NoError>
  18. private let _signal: () -> Signal<Value, NoError>
  19. public var value: Value {
  20. return _value()
  21. }
  22. public var producer: SignalProducer<Value, NoError> {
  23. return _producer()
  24. }
  25. public var signal: Signal<Value, NoError> {
  26. return _signal()
  27. }
  28. /// Initializes a property as a read-only view of the given property.
  29. ///
  30. /// - parameters:
  31. /// - property: A property to read as this property's own value.
  32. public init<P: PropertyType where P.Value == Value>(_ property: P) {
  33. _value = { property.value }
  34. _producer = { property.producer }
  35. _signal = { property.signal }
  36. }
  37. /// Initializes a property that first takes on `initialValue`, then each
  38. /// value sent on a signal created by `producer`.
  39. ///
  40. /// - parameters:
  41. /// - initialValue: Starting value for the property.
  42. /// - producer: A producer that will start immediately and send values to
  43. /// the property.
  44. public init(initialValue: Value, producer: SignalProducer<Value, NoError>) {
  45. let mutableProperty = MutableProperty(initialValue)
  46. mutableProperty <~ producer
  47. self.init(mutableProperty)
  48. }
  49. /// Initializes a property that first takes on `initialValue`, then each
  50. /// value sent on `signal`.
  51. ///
  52. /// - parameters:
  53. /// - initialValue: Starting value for the property.
  54. /// - signal: A signal that will send values to the property.
  55. public init(initialValue: Value, signal: Signal<Value, NoError>) {
  56. let mutableProperty = MutableProperty(initialValue)
  57. mutableProperty <~ signal
  58. self.init(mutableProperty)
  59. }
  60. }
  61. extension PropertyType {
  62. /// Maps the current value and all subsequent values to a new value.
  63. ///
  64. /// - parameters:
  65. /// - transform: A closure that will map the current `value` of this
  66. /// `Property` to a new value.
  67. ///
  68. /// - returns: A new instance of `AnyProperty` who's holds a mapped value
  69. /// from `self`.
  70. public func map<U>(transform: Value -> U) -> AnyProperty<U> {
  71. let mappedProducer = SignalProducer<U, NoError> { observer, disposable in
  72. disposable += ActionDisposable { self }
  73. disposable += self.producer.map(transform).start(observer)
  74. }
  75. return AnyProperty(initialValue: transform(value), producer: mappedProducer)
  76. }
  77. }
  78. /// A property that never changes.
  79. public struct ConstantProperty<Value>: PropertyType {
  80. public let value: Value
  81. public let producer: SignalProducer<Value, NoError>
  82. public let signal: Signal<Value, NoError>
  83. /// Initializes the property to have the given value.
  84. ///
  85. /// - parameters:
  86. /// - value: Property's value.
  87. public init(_ value: Value) {
  88. self.value = value
  89. self.producer = SignalProducer(value: value)
  90. self.signal = .empty
  91. }
  92. }
  93. /// Represents an observable property that can be mutated directly.
  94. ///
  95. /// Only classes can conform to this protocol, because instances must support
  96. /// weak references (and value types currently do not).
  97. public protocol MutablePropertyType: class, PropertyType {
  98. var value: Value { get set }
  99. }
  100. /// A mutable property of type `Value` that allows observation of its changes.
  101. ///
  102. /// Instances of this class are thread-safe.
  103. public final class MutableProperty<Value>: MutablePropertyType {
  104. private let observer: Signal<Value, NoError>.Observer
  105. /// Need a recursive lock around `value` to allow recursive access to
  106. /// `value`. Note that recursive sets will still deadlock because the
  107. /// underlying producer prevents sending recursive events.
  108. private let lock: NSRecursiveLock
  109. /// The getter of the underlying storage, which may outlive the property
  110. /// if a returned producer is being retained.
  111. private let getter: () -> Value
  112. /// The setter of the underlying storage.
  113. private let setter: Value -> Void
  114. /// The current value of the property.
  115. ///
  116. /// Setting this to a new value will notify all observers of any Signals
  117. /// created from the `values` producer.
  118. public var value: Value {
  119. get {
  120. return withValue { $0 }
  121. }
  122. set {
  123. swap(newValue)
  124. }
  125. }
  126. /// A signal that will send the property's changes over time,
  127. /// then complete when the property has deinitialized.
  128. public let signal: Signal<Value, NoError>
  129. /// A producer for Signals that will send the property's current value,
  130. /// followed by all changes over time, then complete when the property has
  131. /// deinitialized.
  132. public var producer: SignalProducer<Value, NoError> {
  133. return SignalProducer { [getter, weak self] producerObserver, producerDisposable in
  134. if let strongSelf = self {
  135. strongSelf.withValue { value in
  136. producerObserver.sendNext(value)
  137. producerDisposable += strongSelf.signal.observe(producerObserver)
  138. }
  139. } else {
  140. /// As the setter would have been deinitialized with the property,
  141. /// the underlying storage would be immutable, and locking is no longer necessary.
  142. producerObserver.sendNext(getter())
  143. producerObserver.sendCompleted()
  144. }
  145. }
  146. }
  147. /// Initializes a mutable property that first takes on `initialValue`
  148. ///
  149. /// - parameters:
  150. /// - initialValue: Starting value for the mutable property.
  151. public init(_ initialValue: Value) {
  152. var value = initialValue
  153. lock = NSRecursiveLock()
  154. lock.name = "org.reactivecocoa.ReactiveCocoa.MutableProperty"
  155. getter = { value }
  156. setter = { newValue in value = newValue }
  157. (signal, observer) = Signal.pipe()
  158. }
  159. /// Atomically replaces the contents of the variable.
  160. ///
  161. /// - parameters:
  162. /// - newValue: New property value.
  163. ///
  164. /// - returns: The previous property value.
  165. public func swap(newValue: Value) -> Value {
  166. return modify { _ in newValue }
  167. }
  168. /// Atomically modifies the variable.
  169. ///
  170. /// - parameters:
  171. /// - action: A closure that accepts old property value and returns a new
  172. /// property value.
  173. /// - returns: The previous property value.
  174. public func modify(@noescape action: (Value) throws -> Value) rethrows -> Value {
  175. return try withValue { value in
  176. let newValue = try action(value)
  177. setter(newValue)
  178. observer.sendNext(newValue)
  179. return value
  180. }
  181. }
  182. /// Atomically performs an arbitrary action using the current value of the
  183. /// variable.
  184. ///
  185. /// - parameters:
  186. /// - action: A closure that accepts current property value.
  187. ///
  188. /// - returns: the result of the action.
  189. public func withValue<Result>(@noescape action: (Value) throws -> Result) rethrows -> Result {
  190. lock.lock()
  191. defer { lock.unlock() }
  192. return try action(getter())
  193. }
  194. deinit {
  195. observer.sendCompleted()
  196. }
  197. }
  198. infix operator <~ {
  199. associativity right
  200. // Binds tighter than assignment but looser than everything else
  201. precedence 93
  202. }
  203. /// Binds a signal to a property, updating the property's value to the latest
  204. /// value sent by the signal.
  205. ///
  206. /// - note: The binding will automatically terminate when the property is
  207. /// deinitialized, or when the signal sends a `Completed` event.
  208. ///
  209. /// ````
  210. /// let property = MutableProperty(0)
  211. /// let signal = Signal({ /* do some work after some time */ })
  212. /// property <~ signal
  213. /// ````
  214. ///
  215. /// ````
  216. /// let property = MutableProperty(0)
  217. /// let signal = Signal({ /* do some work after some time */ })
  218. /// let disposable = property <~ signal
  219. /// ...
  220. /// // Terminates binding before property dealloc or signal's
  221. /// // `Completed` event.
  222. /// disposable.dispose()
  223. /// ````
  224. ///
  225. /// - parameters:
  226. /// - property: A property to bind to.
  227. /// - signal: A signal to bind.
  228. ///
  229. /// - returns: A disposable that can be used to terminate binding before the
  230. /// deinitialization of property or signal's `Completed` event.
  231. public func <~ <P: MutablePropertyType>(property: P, signal: Signal<P.Value, NoError>) -> Disposable {
  232. let disposable = CompositeDisposable()
  233. disposable += property.producer.startWithCompleted {
  234. disposable.dispose()
  235. }
  236. disposable += signal.observe { [weak property] event in
  237. switch event {
  238. case let .Next(value):
  239. property?.value = value
  240. case .Completed:
  241. disposable.dispose()
  242. case .Failed, .Interrupted:
  243. break
  244. }
  245. }
  246. return disposable
  247. }
  248. /// Creates a signal from the given producer, which will be immediately bound to
  249. /// the given property, updating the property's value to the latest value sent
  250. /// by the signal.
  251. ///
  252. /// ````
  253. /// let property = MutableProperty(0)
  254. /// let producer = SignalProducer<Int, NoError>(value: 1)
  255. /// property <~ producer
  256. /// print(property.value) // prints `1`
  257. /// ````
  258. ///
  259. /// ````
  260. /// let property = MutableProperty(0)
  261. /// let producer = SignalProducer({ /* do some work after some time */ })
  262. /// let disposable = (property <~ producer)
  263. /// ...
  264. /// // Terminates binding before property dealloc or
  265. /// // signal's `Completed` event.
  266. /// disposable.dispose()
  267. /// ````
  268. ///
  269. /// - note: The binding will automatically terminate when the property is
  270. /// deinitialized, or when the created producer sends a `Completed`
  271. /// event.
  272. ///
  273. /// - parameters:
  274. /// - property: A property to bind to.
  275. /// - producer: A producer to bind.
  276. ///
  277. /// - returns: A disposable that can be used to terminate binding before the
  278. /// deinitialization of property or producer's `Completed` event.
  279. public func <~ <P: MutablePropertyType>(property: P, producer: SignalProducer<P.Value, NoError>) -> Disposable {
  280. let disposable = CompositeDisposable()
  281. producer
  282. .on(completed: { disposable.dispose() })
  283. .startWithSignal { signal, signalDisposable in
  284. disposable += property <~ signal
  285. disposable += signalDisposable
  286. disposable += property.producer.startWithCompleted {
  287. disposable.dispose()
  288. }
  289. }
  290. return disposable
  291. }
  292. /// Binds `destinationProperty` to the latest values of `sourceProperty`.
  293. ///
  294. /// ````
  295. /// let dstProperty = MutableProperty(0)
  296. /// let srcProperty = ConstantProperty(10)
  297. /// dstProperty <~ srcProperty
  298. /// print(dstProperty.value) // prints 10
  299. /// ````
  300. ///
  301. /// ````
  302. /// let dstProperty = MutableProperty(0)
  303. /// let srcProperty = ConstantProperty(10)
  304. /// let disposable = (dstProperty <~ srcProperty)
  305. /// ...
  306. /// disposable.dispose() // terminate the binding earlier if
  307. /// // needed
  308. /// ````
  309. ///
  310. /// - note: The binding will automatically terminate when either property is
  311. /// deinitialized.
  312. ///
  313. /// - parameters:
  314. /// - destinationProperty: A property to bind to.
  315. /// - sourceProperty: A property to bind.
  316. ///
  317. /// - returns: A disposable that can be used to terminate binding before the
  318. /// deinitialization of destination property or source property
  319. /// producer's `Completed` event.
  320. public func <~ <Destination: MutablePropertyType, Source: PropertyType where Source.Value == Destination.Value>(destinationProperty: Destination, sourceProperty: Source) -> Disposable {
  321. return destinationProperty <~ sourceProperty.producer
  322. }