Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/FluidGroup/DataSources

💾 🔜📱 Type-safe data-driven CollectionView, TableView Framework. (We can also use ASCollectionNode)
https://github.com/FluidGroup/DataSources

collectionview data-driven datasource diff ios rxswift uicollectionview viewcontroller

Last synced: 15 days ago
JSON representation

💾 🔜📱 Type-safe data-driven CollectionView, TableView Framework. (We can also use ASCollectionNode)

Awesome Lists containing this project

README

        



# DataSources
💾 🔜📱 Type-safe data-driven List-UI Framework. (We can also use ASCollectionNode)

Partial updates(insert, delete, move) of UICollectionView/UITableView is important things for fancy UI.

But, It's hard that synchronous of data and UI.

**DataSources** will solve this problem.

![](https://img.shields.io/badge/Swift-3.1-blue.svg?style=flat)
[![CI Status](http://img.shields.io/travis/muukii/DataSources.svg?style=flat)](https://travis-ci.org/muukii/DataSources)
[![Version](https://img.shields.io/cocoapods/v/DataSources.svg?style=flat)](http://cocoapods.org/pods/DataSources)
[![License](https://img.shields.io/cocoapods/l/DataSources.svg?style=flat)](http://cocoapods.org/pods/DataSources)
[![Platform](https://img.shields.io/cocoapods/p/DataSources.svg?style=flat)](http://cocoapods.org/pods/DataSources)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmuukii%2FDataSources.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmuukii%2FDataSources?ref=badge_shield)

![](sample.gif)

## Thanks

**Diff-algorithm**
- Inspired by IGListKit/IGListDiff.
- https://github.com/Instagram/IGListKit
- https://github.com/lxcid/ListDiff

## Features

- Data driven update
- Data did change, then will display.
- Partial updates, no more calling `reloadData`
- Smooth and Faster.
- if the count of changes larger than 300, update with non-animation.
- Simplified usage
- We can use different type each section.
- Type-safe
- We can take clearly typed object by IndexPath.
- Using Adapter-pattern for List-UI
- For example, We can also use this for ASCollectionNode of Texture. (Demo app includes it)
- Reorder by UI operation
- This library is not supported moving between section.

## Requirements

- Swift 4
- iOS 9+

## Usage (Example)

### Conform protocol `Diffable`

```swift
public protocol Diffable {
associatedtype Identifier : Hashable
var diffIdentifier: Identifier { get }
}
```

```swift
struct Model : Diffable {

var diffIdentifier: String {
return id
}

let id: String
}
```

### 🤠 Most Simplified Usage

1. Define `SectionDataController` in ViewController

```swift
let collectionView: UICollectionView

let sectionDataController = SectionDataController(
adapter: CollectionViewAdapter(collectionView: self.collectionView),
isEqual: { $0.id == $1.id } // If Model has Equatable, you can omit this closure.
)

var models: [Model] = [] {
didSet {
sectionDataController.update(items: items, updateMode: .partial(animated: true), completion: {
// Completed update
})
}
}

let dataSource = CollectionViewDataSource(sectionDataController: sectionDataController)

dataSource.cellFactory = { _, collectionView, indexPath, model in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.label.text = model.title
return cell
}

collectionView.dataSource = dataSource
```

### 😎 Semi Manual

#### Single-Section (UICollectionView)

1. Define `SectionDataController` in ViewController

```swift
let collectionView: UICollectionView
var models: [Model]

let sectionDataController = SectionDataController(
adapter: CollectionViewAdapter(collectionView: self.collectionView),
isEqual: { $0.id == $1.id } // If Model has Equatable, you can omit this closure.
)
```

2. Bind Models to `SectionDataController` in ViewController

```swift
var models: [Model] = […] {
didSet {
sectionDataController.update(items: items, updateMode: .partial(animated: true), completion: {
// Completed update
})
}
}
```

3. Implement UICollectionViewDataSource in ViewController

```swift
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return sectionDataController.numberOfItems()
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
let m = sectionDataController.item(for: indexPath)
cell.label.text = m.title
return cell
}
```

#### Multiple-Section (UICollectionView)

1. Define `DataController` in ViewController

```swift
let collectionView: UICollectionView
var models: [Model]

let dataController = DataController(adapter: CollectionViewAdapter(collectionView: self.collectionView))
```

2. Define `Section` in ViewController

```swift
let section0 = Section(ModelA.self, isEqual: { $0.id == $1.id })
let section1 = Section(ModelB.self, isEqual: { $0.id == $1.id })
```

3. Add `Section` to `DataController`

Order of Section will be decided in the order of addition.

```swift
dataController.add(section: section0) // will be 0 of section
dataController.add(section: section1) // will be 1 of section
```

4. Bind Models to DataController

```swift
var section0Models: [ModelA] = […] {
didSet {
dataController.update(
in: section0,
items: section0Models,
updateMode: .partial(animated: true),
completion: {

})
}
}

var section1Models: [ModelA] = […] {
didSet {
dataController.update(
in: section1,
items: section1Models,
updateMode: .partial(animated: true),
completion: {

})
}
}
```

5. Implement UICollectionViewDataSource

```swift
func numberOfSections(in collectionView: UICollectionView) -> Int {
return dataController.numberOfSections()
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataController.numberOfItems(in: section)
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

return dataController.item(
at: indexPath,
handlers: [
.init(section: section0) { (m: ModelA) in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.label.text = m.title
return cell
},
.init(section: section1) { (m: ModelB) in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.label.text = m.title
return cell
},
])

/* Other way
switch indexPath.section {
case section0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
let m = _dataController.item(at: indexPath, in: section0)
cell.label.text = m.title
return cell
case section1:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
let m = _dataController.item(at: indexPath, in: section1)
cell.label.text = m.title
return cell
default:
fatalError()
}
*/
}
```

## Reorder by UI operation

`SectionDataController` has a snapshot for `List-UI`.
It helps that perform batch update List-UI in safety.

But, the snapshots include side-effects.
For example, if we did reorder items of `List-UI` by UI operation.
In this time, Items of List-UI is caused differences to the snapshot.
It will be caused unnecessary diff.

Therefore when we reorder items, we should operation followings.

0. Reorder items of UI
1. Call `SectionDataController.reserveMoved(...`
2. Reorder items of Array
3. Call `SectionDataController.update(items: [T]..`

# Demo Application

This repository include Demo-Application.
You can touch DataSources.

1. Clone repository.

```
$ git clone https://github.com/muukii/DataSources.git
$ cd DataSources
$ pod install
```

2. Open xcworkspace
3. Run `DataSourcesDemo` on iPhone Simulator.

# Author

muukii, [email protected], https://muukii.me/

# License

**DataSources** is available under the MIT license. See the LICENSE file for more info.

[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmuukii%2FDataSources.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmuukii%2FDataSources?ref=badge_large)