Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/alexdrone/Buffer

Swift μ-framework for efficient array diffs and datasource adapters.
https://github.com/alexdrone/Buffer

buffer datasource diffing edit-distance iglistkit ios keypath kvo levenshtein-distance swift swift-3 tableview

Last synced: about 1 month ago
JSON representation

Swift μ-framework for efficient array diffs and datasource adapters.

Awesome Lists containing this project

README

        

# Buffer [![Swift](https://img.shields.io/badge/swift-5-orange.svg?style=flat)](#) [![Platform](https://img.shields.io/badge/platform-iOS|macOS-lightgrey.svg?style=flat)](#) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://opensource.org/licenses/MIT)

Buffer

Swift μ-framework for efficient array diffs, collection observation and data source implementation.

[C++11 port here](https://github.com/alexdrone/libbuffer)

### Installation

```bash
cd {PROJECT_ROOT_DIRECTORY}
curl "https://raw.githubusercontent.com/alexdrone/Buffer/master/bin/dist.zip" > dist.zip && unzip dist.zip && rm dist.zip;
```

Drag `Buffer.framework` in your project and add it as an embedded binary.

If you use [xcodegen](https://github.com/yonaskolb/XcodeGen) add the framework to your *project.yml* like so:

```yaml
targets:
YOUR_APP_TARGET:
...
dependencies:
- framework: PATH/TO/YOUR/DEPS/Buffer.framework
```

## Installation with CocoaPods/Carthage (deprecated)

If you are using **CocoaPods**:

Add the following to your [Podfile](https://guides.cocoapods.org/using/the-podfile.html):

```ruby
pod 'Buffer'
```

If you are using **Carthage**:

To install Carthage, run (using Homebrew):

```bash
$ brew update
$ brew install carthage
```

Then add the following line to your `Cartfile`:

```
github "alexdrone/Buffer" "master"
```

# Getting started

Buffer is designed to be very granular and has APIs with very different degrees of abstraction.

### Managing a collection with Buffer

You can initialize and use **Buffer** in the following way.

```swift

import Buffer

class MyClass: BufferDelegate {

lazy var buffer: Buffer = {
// The `sort` and the `filter` closure are optional - they are a convenient way to map the src array.
let buffer = Buffer(initialArray: self.elements, sort: { $0.bar > $1.bar }, filter: { $0.isBaz })
buffer.delegate = self
}()

var elements: [Foo] = [Foo]() {
didSet {
// When the elements are changed the buffer object will compute the difference and trigger
// the invocation of the delegate methods.
// The `synchronous` and `completion` arguments are optional.
self.buffer.update(with: newValues, synchronous: false, completion: nil)
}
}

//These methods will be called when the buffer has changedd.

public func buffer(willChangeContent buffer: BufferType) {
//e.g. self.tableView?.beginUpdates()

}

public func buffer(didDeleteElementAtIndices buffer: BufferType, indices: [UInt]) {
//e.g. Remove rows from a tableview
}

public func buffer(didInsertElementsAtIndices buffer: BufferType, indices: [UInt]) {
}

public func buffer(didChangeContent buffer: BufferType) {
}

public func buffer(didChangeElementAtIndex buffer: BufferType, index: UInt) {
}

public func buffer(didMoveElement buffer: BufferType, from: UInt, to: UInt) {
}

public func buffer(didChangeAllContent buffer: BufferType) {
}
}

```

### Built-in UITableView and UICollectionView adapter

One of the main use cases for **Buffer** is probably to apply changes to a TableView or a CollectionView.
**Buffer** provides 2 adapter classes that implement the `BufferDelegate` protocol and automatically perform the required
changes on the target tableview/collectionview when required.

```swift

import Buffer

class MyClass: UITableViewController {

lazy var buffer: Buffer = {
// The `sort` and the `filter` closure are optional - they are convenient way to map the src array.
let buffer = Buffer(initialArray: self.elements, sort: { $0.bar > $1.bar }, filter: { $0.isBaz })
buffer.delegate = self
}()

var elements: [Foo] = [Foo]() {
didSet {
// When the elements are changed the buffer object will compute the difference and trigger
// the invocation of the delegate methods.
// The `synchronous` and `completion` arguments are optional.
self.buffer.update(with: newValues, synchronous: false, completion: nil)
}
}

let adapter: TableViewDiffAdapter!

init() {
super.init()
self.adapter = TableViewDiffAdapter(buffer: self.buffer, view: self.tableView)

// Additionaly you can let the adapter be the datasource for your table view by passing a cell
// configuration closure to the adpater.
adapter.useAsDataSource { (tableView, object, indexPath) -> UITableViewCell in
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell")
cell?.textLabel?.text = object.foo
return cell
}
}

}

```

### Component-Oriented TableView

Another convenient way to use **Buffer** is through the `Buffer.TableView` class.
This abstraction allows for the tableView to reconfigure itself when its state (the elements) change.

```swift

import Buffer

class ViewController: UIViewController {

lazy var tableView: TableView = {
let tableView = TableView()
return tableView
}()

lazy var elements: [ListItem] = {
var elements = [ListItem]()
for _ in 0...100 {
// AnyListItem wraps the data and the configuration for every row in the tableview.
let item = ListItem(type: UITableViewCell.self,
container: self.tableView,
model: FooModel(text: "Foo"))) {
cell, model in
cell.textLabel?.text = model.text
}
elements.append(item)
}
return elements
}()

override func viewDidLayoutSubviews() {
self.tableView.frame = self.view.bounds
}

override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.tableView)
self.tableView.elements = self.elements
}
}

```

Check the demo out to learn more about Buffer.

### Credits

- Diff algorithm from IGListKit/IGListDiff
* [IGListKit original ObjC++ implementation](https://github.com/Instagram/IGListKit)
* [ListDiff Swift port](https://github.com/lxcid/ListDiff)