Simple React in Swift
RxStream is a simpler kind of Reactive framework for Swift that seeks to integrate well into existing language and architectural paradigms instead of replacing them.
If you’re looking for a full Reactive framework, you’d probably be best taking a look at RxSwift or ReactiveCocoa. In contrast to these, RxStream is a much pared down version of React. The motivation for this is several fold:
- With a simpler paradigm, the learning curve is a lot shorter. It’s easier to get other developers to invest into using it.
- RxStream tries hard to divest itself of some of the more obscure syntax and complications that seem inherent in most Reactive frameworks. This can help create more readable and maintainable code.
- Whereas many proponents of React advocate it as a replacement for many existing architectures and software solutions, RxStream was designed mostly as a supplement to the paradigms you’re already using. It’s designed to enhance and integrate into Swift’s inherit language features instead of ignoring or replacing them. Use RxStream as little or as much as you’d like. It won’t get in your way.
Note: If you’re new to React, you may want take a look at the introduction to Reactive at ReactiveX. This will help you get a good grasp on some of the core principles of React. However, some terms they use may be different than what RxStream uses.
RxStream operates around the idea of a transforming stream of values. If you’re familiar with ReactiveX, their Observable<T>
would be the closest comparable to RxStream’s Stream<T>
. All streams have a variety of relevant operations that observe and transform the stream’s values. However, with RxStream, there is a very clear distinction between the types of streams created and returned. This removes any uncertainty about what the stream is, how it operates, and what the client can expect from it:
- Hot: A Hot stream is a kind of stream that produces values with no regard or input from it’s clients. When a client registers operations on a Hot stream, it will receive values as they come.
- Cold: A Cold stream only produces values when a client makes a
Request
. Unlike all other streams, a Cold stream has two types:Request
andResponse
. A client makes aRequest
and receive aResponse
from the Cold stream. - Future: A future is a stream that produces only one value and then closes.
- Progression: A Progression is a special type of Future that reports the progress of a task. It allows the client to observe the progress and respond to it as well as the final result.
- Promise: A type of future that produces only one value, but it can be cancelled and retried by it’s client until it produces an error or a valid value.
- Observable: An observable is a kind of Hot Stream who’s value is guaranteed and can be directly observed and accessed outside of the stream.
- Timer: This is a concrete Hot Stream that emits an event repeatedly on a predefined interval. While you can create your own timer by creating a
HotTask
, because ofFoundation.Timer
's retaining behavior, it can be tricky to do this without creating a retain cycle. SoRx.Timer
has been created to provide an easier way.
Hot and Observable streams have subclasses used for producing the values. While Cold, Promise and Future streams can only be initialized with a Task (that generates the value).
RxStream has several features that help you manage and use them easily.
- Dispatch: All streams can have their operations done on a specified dispatch (which uses GCD under the hood). This allows you to easily perform your operations on the main queue, a background queue or a custom queue you create.
- Throttle: A throttle allows you to control the flow of data being passed own the streams. One of the most useful is a Pressure Throttle, which will buffer processing and prevent too many values from being processed based on the current work load.
- Disposal: Instead of using separate object(s) to dispose of processing chains, RxStream allows you to dispose of streams intuitively and specifically within the chain itself. When any part of a stream terminates, that entire branch will be pruned. Plus, you can easily specify when a branch terminates by using explicit
doWhile
oruntil
operators or even tie the lifetime of the branch to a specific object. - Replay: Streams can optionally be replayed, which will pull down the last value of a stream (if any) when creating a processing chain from an existing stream. Simply call
replay()
at the end of a processing chain, if there is a prior value available it will be pulled into the processing chain. Both Future and Promise streams will auto-replay a completed value into any new processing chain by default. - Operations: Each stream features a wide range of operations you can use to process your data. However, we have avoided more complex operators, specifically those operators that produce or work on streams that contain other streams. This is the primary area that RxStream differs from other Reactive frameworks.
- Clear Terminators: Each stream terminates with clear language, defined by an enum:
case .cancelled
: The stream has been cancelled.case .completed
: The stream has been completed.case .error(Error)
: The stream has terminated with an error.
- Non-terminating Errors: In addition to the normal values, non-terminating errors can also be pushed into the stream and observed. These errors can be turned into terminating errors down stream.
- Construction: Constructing processing chains on a stream is the process of subscribing. There’s no need manually call
subscribe
to start receiving values. It’s rare for a developer to need to construct a chain without actually using it, so instead of forcing you to callsubscribe
, if you don’t want to receive values, instead usefilter
to filter them out until you are ready. - Debugging: RxStream has several features to allow for easier debugging, including descriptive
debugDescription
and custom debug log handlers on both the individual Stream and global spaces.
- Swift 4.0
- XCode 9.0
- iOS 8.1+ | MacOS 10.10+ | tvOS 9.0+ | watchOS 2.0+
- Note: For Swift 3 projects, you can either use version 1.x or the Swift 3 branch.*
- Issues & Bugs: Please file an issue on GitHub.
- Feature Request: Please file an issue on GitHub.
- Contact Me: aaron@flexile.co
- Blog: Functional Gibberish