raccommunity / reactivecollections Goto Github PK
View Code? Open in Web Editor NEWReactive collections for Swift using ReactiveSwift ๐ ๐ ๐
License: MIT License
Reactive collections for Swift using ReactiveSwift ๐ ๐ ๐
License: MIT License
ReactiveArray
can be made a generic container of any range replaceable collection.
When iterating on #25, I just realise a couple of things:
When we observe unordered collections, e.g. Dictionary
and Set
, what we care about are just the elements. That is unlike the indices of an Array
which also indicate the stable element order.
These collections have varying, loose index invalidation model, which makes generating indices of the changes non-trivial.
With such divergence, there is no point for a generic abstraction for everything, nor can unordered collections interoperate in generic algorithms written for ordered collections anyway.
For unordered collections, an alternative delta protocol that concerns just the values is proposed:
public protocol ElementDelta {
associatedtype Elements: Collection
var inserts: Elements { get }
var deletes: Elements { get }
var updates: Elements { get }
}
On top of the protocol, we can:
Delta
with conformance to ElementDelta
.elementDeltas
producer on ReactiveArray
, which derives element deltas from the indexing delta.A spin off from #1 (comment).
A similar question is floating in my mind too: if we meant to go full FRP, embraces immutability and represents stuff as streams of values, perhaps ReactiveArray
should only be an producer-facing imperative bridge only.
Then the consumer facing API of a reactive collection should have only a signal
that emits the changeset (index + corresponding value), and a producer
that emits the full collection when started, following by subsequent changesets. e.g.
enum CollectionEvent<Element, C: Collection> where C.Iterator.Element == Element {
case reloaded(C)
case changed(ChangeSet<Element>)
}
Let's say ReactiveSequence
is the "read-only" time-based sequence wrapper.
let candies = ReactiveSequence(ReactiveArray<Candy>())
YES
candies.producer // SignalProducer<CollectionEvent<Candy>, NoError>
candies.signal // Signal< CollectionEvent<Candy>, NoError>
NOOOO
candies[0] // My name is no, my sign is no, my number is no.
It would be up to the consumer to reproduce the array as needed, e.g. collection view adapters.
In this case, we do not need to worry about:
how to wrap and pass the collections between layers, as they would be streams of CollectionEvent
and Changeset
after all.
This bothered me a lot when dealing with live updating collections across layers, and it seems finally we would have a definite solution.
asynchronous observations, as observers can rely on the changesets from the stream to reproduce the sequence asynchronously, instead of referring back to the mutable backing store i.e. ReactiveArray
.
Simplify the roundtrip for live updating collections for both MVVM and VIPER (if anyone ever uses it with RAS).
It might seem a huge leap for not exposing a Collection
interface that allows direct access for consumers. But I would argue that it is a radically different case from Property
in the sense that:
Property.value
is a relaxed atomic read.
Sequences of calls to a Collection
is non-atomic, non threadsafe. Let alone if the observer is not synchronous, one would have a changeset that might not match the state at all. Direct manipulation should therefore IMO be discouraged.
Property
types are a primitive imperative bridge โ say you got a trigger event and you read values out from multiple Property
s in some weird interoperating scenarios with the imperative world.
But IMO reactive collections are primarily (1) observed for delta changes & react; and (2) adapted with an intermediate layer as collection view data sources. Both can work without the collection itself exposes an imperative Collection
interface if the stream has already packed with values.
It is easier to add something should the requirement prevail, than taking something back.
Well I had an idea when iterating on #19, but it feels better to get to it after #19 lands.
Specifically, it would be "automatic" in bindings:
tableView.collection <~ viewModel.lazyItems.producer
i.e. the same as normal bindings.
The binding system provides a more specific implementation when Delta
statically satisfies Snapshot.Element: LazyPropertyProtocol
(or the inner delta's one for 2D collection), and turn on the prefetching support automatically.
The LazyPropertyProtocol
would be probably like:
public protocol LazyPropertyProtocol: PropertyProtocol {
public enum Event {
case shouldPrefetch
case stopPrefetch
case clear
}
var event: BindingTarget<Event> { get }
}
It is a Property
with:
shouldPrefetch
event is received, value.get
is accessed the first time, or the producer is started.A default implementation LazyProperty
would be provided.
Prototype: ReactiveCocoa/ReactiveSwift#494
SectionedChangeset
that builds on top of Changeset
.Snapshot
or introduce SectionedSnapshot
for nested, two-level collections.ReactiveArray
is a one-dimensional collection. While it is sufficient for many uses, almost all Cocoa collection views expect a two-dimensional backing.
While in theory a nested ReactiveArray
might sufficiently serve as a backing (presumably in the model layer), there are still problems to be solved:
The collection index: ReactiveArray
uses Int
at this moment. How can collection be nested with the indexes being properly aggregated & nested? A separated NestedReactiveArray
that uses IndexPath
seems inevitable, unless ReactiveArray
uses IndexPath
.
Layering: Mapping from model layer to view model layer & Encapsulation.
How can additional section information blend in?
How would the binding process look like? Stream operators or imperative?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.