Giter Site home page Giter Site logo

jagatbaraiya / datasources Goto Github PK

View Code? Open in Web Editor NEW

This project forked from fluidgroup/datasources

0.0 2.0 0.0 4.56 MB

๐Ÿ’พ ๐Ÿ”œ๐Ÿ“ฑ Type-safe data-driven CollectionView, TableView Framework. (We can also use ASCollectionNode)

License: MIT License

Ruby 2.10% Swift 96.63% Objective-C 1.27%

datasources's Introduction

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.

CI Status Version License Platform Carthage compatible

Thanks

Diff-algorithm

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

public protocol Diffable {
  associatedtype Identifier : Hashable
  var diffIdentifier: Identifier { get }
}
struct Model : Diffable {

  var diffIdentifier: String {
    return id
  }
  
  let id: String
}

๐Ÿค  Most Simplified Usage

  1. Define SectionDataController in ViewController
let collectionView: UICollectionView

let sectionDataController = SectionDataController<Model, CollectionViewAdapter>(
  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
let collectionView: UICollectionView
var models: [Model]

let sectionDataController = SectionDataController<Model, CollectionViewAdapter>(
  adapter: CollectionViewAdapter(collectionView: self.collectionView),
  isEqual: { $0.id == $1.id } // If Model has Equatable, you can omit this closure.
)
  1. Bind Models to SectionDataController in ViewController
var models: [Model] = [โ€ฆ] {
  didSet {
    sectionDataController.update(items: items, updateMode: .partial(animated: true), completion: {
      // Completed update
    })
  }
}
  1. Implement UICollectionViewDataSource in ViewController
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
let collectionView: UICollectionView
var models: [Model]

let dataController = DataController<CollectionViewAdapter>(adapter: CollectionViewAdapter(collectionView: self.collectionView))
  1. Define Section<T> in ViewController
let section0 = Section(ModelA.self, isEqual: { $0.id == $1.id })
let section1 = Section(ModelB.self, isEqual: { $0.id == $1.id })
  1. Add Section to DataController

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

dataController.add(section: section0) // will be 0 of section
dataController.add(section: section1) // will be 1 of section
  1. Bind Models to DataController
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: {
        
    })
  }
}
  1. Implement UICollectionViewDataSource
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.

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

Appendix

Combination with RxSwift

We can use DataControllers with RxSwift. The following code is an example.

Add extension

import RxSwift
import DataControllers

extension SectionDataController : ReactiveCompatible {}

extension Reactive where Base : SectionDataControllerType {

  public func partialUpdate<
    T,
    Controller: ObservableType
    >
    (animated: Bool) -> (_ o: Source) -> Disposable where Source.E == [T], T == Base.ItemType {

    weak var t = base.asSectionDataController()

    return { source in

      source
        .observeOn(MainScheduler.instance)
        .concatMap { (newItems: [T]) -> Completable in
          Completable.create { o in
            guard let sectionDataController = t else {
              o(.completed)
              return Disposables.create()
            }
            sectionDataController.update(items: newItems, updateMode: .partial(animated: animated), completion: {
              o(.completed)
            })
            return Disposables.create()
          }
        }
        .subscribe()
    }
  }
}
let models: Variable<[Model]>
let sectionDataController = SectionDataController<Model, CollectionViewAdapter>

models
  .asDriver()
  .drive(sectionDataController.rx.partialUpdate(animated: true))

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
  1. Open xcworkspace
  2. Run DataSourcesDemo on iPhone Simulator.

Installation

CocoaPods

pod 'DataSources'

Carthage

github "muukii/DataSources"

You need to add DataSources.framework and Diff.framework to your project.

Author

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

License

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

datasources's People

Contributors

muukii avatar

Watchers

 avatar  avatar

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.