Skip to content

Hot-swappable reactive collection supporting Realm, Core Data and regular arrays.

License

Notifications You must be signed in to change notification settings

iandundas/HotTakeCore

Repository files navigation

HotTake

Current release: v0.9.1

HotTake builds on the functionality of the CollectionProperty type from ReactiveKit 2.

It provides a reactive Collection that is driven by any observable backing datasource (currently supporting Realm, a regular Array and, coming soon, CoreData) which can be "hot-swapped" to another datasource on the fly, providing any observers with a diff of what's changed, and then re-binding to the underlying datasource to continue delivering their own ChangeSets.

Realm adapter:

For Realm this comes via the Realm Change Notifications, for CoreData this comes via NSFetchedResultsController, and for static Arrays this comes from the inherent ability of ReactiveKit's CollectionProperty to diff (Equatable-conforming) Arrays.

For example, using the Realm adapter, a Realm query Result<Cat> of Cat objects could be plugged into HotTake.Container, and bound to a TableView. Any changes to the Realm would be reflected in the tableView automatically. You could then swap the Realm adapter out for a static array of Cat objects - any Observers would receive the diff of what changed (and what did not). In turn, you could then swap in any other DataSource containing Cats and it would react to that new collection, providing you a diff.

e.g. you might do the following (download example):

  • Plug in a Realm query Result<Cat>:
  • Insert new items into Realm
  • Receive the change (it uses Realm Notifications under the hood), and present on the tableView
  • Swap in a specific Array of Cats (in this case, a simple array pulled from Realm for demonstration purposes, but it could be anything), separate to the Realm result
  • Receive the diff

Post-Sort

Datasources can also be chained. For example, there is a PostSort adapter which can be added to the chain to provide your own sorting, separate from the underlying datasource.

This was useful in my app Tacks, because I needed to sort my Realm query results by distance from my current location, whilst also preserving the ability to observe the array and receive diffs when the underlying dataset changed.

  // Apply post-sort over the Realm datasource:
  datasource = RealmDataSource(items: result).postSort() { (a: Place, b:Place) in
      return ascending
          ? a.location.distanceFromLocation(currentLocation) < b.location.distanceFromLocation(currentLocation)
          : a.location.distanceFromLocation(currentLocation) > b.location.distanceFromLocation(currentLocation)
  }

It is not possible to query Realm like this otherwise.

Note: you must provide a sorted RealmQuery as input to PostSortDataSource, because "Note that the order of Results is only guaranteed to stay consistent when the query is sorted." (realm docs)[https://realm.io/docs/swift/latest/#sorting]

Requirements:

  • Xcode 8
  • Swift 2.3 (will support v3.0 soon)
  • ReactiveKit 2.1.1 (will support v3.0 soon)
  • iOS only, currently

Usage

more detailed instructions coming soon. There is a demo app here:

Creating your datasource:

Array DataSource:

let arrayDataSource = ManualDataSource<Cat>(items: cats)

Realm DataSource:

  let realm = try! RealmSwift.Realm(configuration: RealmSwift.Realm.Configuration(inMemoryIdentifier: sharedRealmID))
  let result = realm.objects(Cat).sorted("miceEaten")
  let realmDataSource = RealmDataSource(items: result)

Creating your container:

let container = Container<Cat>(datasource: realmDataSource.eraseType())

Binding and Observing:

HotTake is built on top of ReactiveKit, so you can use this powerful Functional Reactive library to observe the mutations, and to bind to e.g. a UITableView:

container.collection.observeNext { (changeset) in
    print("Changeset: \(changeset)\n\n")
}.disposeIn(rBag)

// Bind container to TableView:
container.collection.bindTo(tableView) {
    (indexPath, items, tableView) -> UITableViewCell in

    let item = items[indexPath.row]
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
    cell.textLabel?.text = item.name
    return cell

}.disposeIn(rBag)

Installation:

Carthage:

  • Add the following line to your Cartfile:

github "iandundas/HotTakeRealm"

  • Run the following;

carthage update --toolchain com.apple.dt.toolchain.Swift_2_3 --platform iOS

  • Add the built frameworks to your project as described on Carthage, as well as adding each to the Embed Frameworks build phase.

Cocoapods

coming soon

About

Hot-swappable reactive collection supporting Realm, Core Data and regular arrays.

Resources

License

Stars

Watchers

Forks

Packages

No packages published