GithubHelp home page GithubHelp logo

raccommunity / reactivecollections Goto Github PK

View Code? Open in Web Editor NEW
40.0 40.0 5.0 125 KB

Reactive collections for Swift using ReactiveSwift ๐Ÿš— ๐Ÿš• ๐Ÿš™

License: MIT License

Swift 93.20% Objective-C 0.71% Ruby 1.28% Shell 4.81%

reactivecollections's People

Contributors

andersio avatar dmcrodrigues avatar ikesyo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactivecollections's Issues

Differentiate indexing delta and element delta.

When iterating on #25, I just realise a couple of things:

  1. 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.

  2. 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:

  1. Restructure Delta with conformance to ElementDelta.
  2. Expose a new elementDeltas producer on ReactiveArray, which derives element deltas from the indexing delta.

Read-only view for collection consumers

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:

  1. 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.

  2. 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.

  3. 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:

  1. 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.

  2. Property types are a primitive imperative bridge โ€” say you got a trigger event and you read values out from multiple Propertys 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.

  3. It is easier to add something should the requirement prevail, than taking something back.

Prefetching support

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:

  1. the initial value also serving as the reset value; and
  2. a side effect that would be invoked once since last reset when a shouldPrefetch event is received, value.get is accessed the first time, or the producer is started.

A default implementation LazyProperty would be provided.

Interacting with Collection Views

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:

  1. 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.

  2. Layering: Mapping from model layer to view model layer & Encapsulation.

  3. How can additional section information blend in?

  4. How would the binding process look like? Stream operators or imperative?

Support batch updates

This was suggested in #1 by @andersio and it's a great idea as an optimization for cases where we want to group a set of changes into a single one.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.