Giter VIP home page Giter VIP logo

fehrim / dtcollectionviewmanager Goto Github PK

View Code? Open in Web Editor NEW

This project forked from dentelezhkin/dtcollectionviewmanager

0.0 2.0 0.0 622 KB

Protocol-oriented UICollectionView management, powered by generics and associated types.

Home Page: http://digginginswift.com/2015/09/13/dttableviewmanager-4-protocol-oriented-uitableview-management-in-swift

License: MIT License

Ruby 0.64% Swift 98.16% Makefile 1.20%

dtcollectionviewmanager's Introduction

Build Status   codecov.io CocoaPod platform   CocoaPod version   Carthage compatible Packagist DTCollectionViewManager 4

This is a sister-project for DTTableViewManager - great tool for UITableView management, built on the same principles.

Powerful protocol-oriented UICollectionView management framework, written in Swift 2.

Features

  • Powerful mapping system between data models and cells, headers and footers
  • Support for all Swift types - classes, structs, enums, tuples
  • Support for protocols and subclasses as data models
  • Views created from code, XIB, or storyboard
  • Flexible Memory/CoreData/Custom storage options
  • Support for Realm.io databases
  • Automatic datasource and interface synchronization.
  • Automatic XIB registration and dequeue
  • No type casts required
  • No need to subclass
  • Can be used with UICollectionViewController, or UIViewController with UICollectionView, or any other class, that contains UICollectionView

Requirements

  • Xcode 7 and higher
  • iOS 8 and higher / tvOS 9.0 and higher
  • Swift 2

Installation

CocoaPods:

pod 'DTCollectionViewManager', '~> 4.5.0'

Carthage:

github "DenHeadless/DTCollectionViewManager"  ~> 4.5.0

After running carthage update drop DTCollectionViewManager.framework and DTModelStorage.framework to Xcode project embedded binaries.

Quick start

DTCollectionViewManager framework has two parts - core framework, and storage classes. Import them both to your view controller class to start:

import DTCollectionViewManager
import DTModelStorage

The core object of a framework is DTCollectionViewManager. Declare your class as DTCollectionViewManageable, and it will be automatically injected with manager property, that will hold an instance of DTCollectionViewManager.

First, make sure your UICollectionView outlet is wired to your class.

Important Your UICollectionView outlet should be declared as optional:

  @IBOutlet weak var collectionView: UICollectionView?

Call startManagingWithDelegate: to initiate UICollectionView management:

    manager.startManagingWithDelegate(self)

Let's say you have an array of Posts you want to display in UICollectionView. To quickly show them using DTCollectionViewManager, here's what you need to do:

  • Create UICollectionViewCell subclass, let's say PostCell. Adopt ModelTransfer protocol
class PostCell : UICollectionViewCell, ModelTransfer
{
	func updateWithModel(model: Post)
	{
		// Fill your cell with actual data
	}
}
  • Call registration methods on your DTCollectionViewManageable instance
	manager.registerCellClass(PostCell)

ModelType will be automatically gathered from your PostCell. If you have a PostCell.xib file, it will be automatically registered for PostCell. If you have a storyboard with PostCell, set it's reuseIdentifier to be identical to class - "PostCell".

  • Add your posts!
	manager.memoryStorage.addItems(posts)

That's it! It's that easy!

Mapping and registration

  • registerCellClass:
  • registerNibNamed:forCellClass:
  • registerHeaderClass:
  • registerNibNamed:forHeaderClass:
  • registerFooterClass:
  • registerNibNamed:forFooterClass:
  • registerSupplementaryClass:forKind:
  • registerNibNamed:forSupplementaryClass:forKind:
  • registerNiblessSupplementaryClass:forKind:

For more detailed look at mapping in DTCollectionViewManager, check out dedicated Mapping wiki page.

Data models

Starting from 4.4.0 release, DTCollectionViewManager supports all Swift and Objective-C types as data models. This also includes protocols and subclasses. So now this works:

protocol Food {}
class Apple : Food {}
class Carrot: Food {}

class FoodCollectionViewCell : UICollectionViewCell, ModelTransfer {
    func updateWithModel(model: Food) {
        // Display food in a cell
    }
}
manager.registerCellClass(FoodCollectionViewCell)
manager.memoryStorage.addItems([Apple(),Carrot()])

Mappings are resolved simply by calling is type-check. In our example Apple is Food and Carrot is Food, so mapping will work.

Customizing mapping resolution

There can be cases, where you might want to customize mappings based on some criteria. For example, you might want to display model in several kinds of cells:

class FoodTextCell: UICollectionViewCell, ModelTransfer {
    func updateWithModel(model: Food) {
        // Text representation
    }
}

class FoodImageCell: UICollectionViewCell, ModelTransfer {
    func updateWithModel(model: Food) {
        // Photo representation
    }
}

manager.registerCellClass(FoodTextCell)
manager.registerCellClass(FoodImageCell)

If you don't do anything, FoodTextCell mapping will be selected as first mapping, however you can adopt DTViewModelMappingCustomizable protocol to adjust your mappings:

extension PostViewController : DTViewModelMappingCustomizable {
    func viewModelMappingFromCandidates(candidates: [ViewModelMapping], forModel model: Any) -> ViewModelMapping? {
        if let foodModel = model as? Food where foodModel.hasPhoto {
            return candidates.last
        }
        return candidates.first
    }
}

DTModelStorage

DTModelStorage is a framework, that provides storage classes for DTCollectionViewManager. By default, storage property on DTCollectionViewManager holds a MemoryStorage instance.

MemoryStorage

MemoryStorage is a class, that manages UICollectionView models in memory. It has methods for adding, removing, replacing, reordering collection view models etc. You can read all about them in DTModelStorage repo. Basically, every section in MemoryStorage is an array of SectionModel objects, which itself is an object, that contains optional header and footer models, and array of collection items.

NSFetchedResultsController and CoreDataStorage

CoreDataStorage is meant to be used with NSFetchedResultsController. It automatically monitors all NSFetchedResultsControllerDelegate methods and updates UI accordingly to it's changes. All you need to do to display CoreData models in your UICollectionView, is create CoreDataStorage object and set it on your storage property of DTCollectionViewManager.

Keep in mind, that MemoryStorage is not limited to objects in memory. For example, if you have CoreData database, and you now for sure, that number of items is not big, you can choose not to use CoreDataStorage and NSFetchedResultsController. You can fetch all required models, and store them in MemoryStorage.

RealmStorage

RealmStorage is a class, that is meant to be used with realm.io databases. To use RealmStorage with DTCollectionViewManager, add following line to your Podfile:

    pod 'DTModelStorage/Realm'

If you are using Carthage, RealmStorage will be automatically built along with DTModelStorage.

Subclassing storage classes

For in-depth look at how subclassing storage classes can improve your code base, read this article on wiki.

Reacting to events

Method pointers

There are two types of events reaction. The first and recommended one is to pass method pointers to DTCollectionViewManager. For example, selection:

manager.cellSelection(PostViewController.selectedPost)

func selectedPost(cell: PostCell, post: Post, indexPath: NSIndexPath) {
  // Do something with Post
}

DTCollectionViewManager automatically breaks retain cycles, that can happen when you pass method pointers around. There's no need to worry about [weak self] stuff.

There are also methods for configuring cells, headers and footers:

manager.cellConfiguration(PostViewController.configurePostCell)
manager.headerConfiguration(PostViewController.configurePostsHeader)
manager.footerConfiguration(PostViewController.configurePostsFooter)
manager.supplementaryConfiguration(kind: UICollectionElementKindSectionHeader, PostViewController.configurePostsSupplementary)

And of course, you can always use dynamicType instead of directly referencing type name:

manager.cellSelection(self.dynamicType.selectedPost)

Another way of dealing with events, is registrating closures.

Important

Unlike methods with method pointers, all events with closures are stored on DTCollectionViewManager instance, so be sure to declare [weak self] in capture lists to prevent retain cycles.

Selection

Instead of reacting to cell selection at UICollectionView NSIndexPath, DTCollectionViewManager allows you to react when user selects concrete model:

  manager.whenSelected(PostCell.self) { postCell, post, indexPath in
      print("Selected \(post) in \(postCell) at \(indexPath)")
  }

Thanks to generics, postCell and post are already a concrete type, there's no need to check types and cast. There' also a shortcut to registration and selection method:

  manager.registerCellClass(PostCell.self, whenSelected: { postCell, post, indexPath in })

Configuration

Although in most cases your cell can update it's UI with model inside updateWithModel: method, sometimes you may need to additionally configure it from controller. There are four events you can react to:

  manager.configureCell(PostCell.self) { postCell, post, indexPath in }
  manager.configureHeader(PostHeader.self) { postHeader, postHeaderModel, sectionIndex in }
  manager.configureFooter(PostFooter.self) { postFooter, postFooterModel, sectionIndex in }
  manager.configureSupplementary(PostSupplementary.self) { postSupplementary, postSupplementaryModel, sectionIndex in}

Headers are supplementary views of type UICollectionElementKindSectionHeader, and footers are supplementary views of type UICollectionElementKindSectionFooter.

Content updates

Sometimes it's convenient to know, when data is updated, for example to hide UICollectionView, if there's no data. Conform to DTCollectionViewContentUpdatable protocol and implement one of the following methods:

extension PostsViewController: DTCollectionViewContentUpdatable {
  func beforeContentUpdate() {

  }

  func afterContentUpdate() {

  }
}

UICollectionViewDelegate and UICollectionViewDatasource

DTCollectionViewManager serves as a datasource and the delegate to UICollectionView. However, it implements only some of UICollectionViewDelegate and UICollectionViewDatasource methods, other methods will be redirected to your controller, if it implements it.

Convenience model getters

There are several convenience model getters, that will allow you to get data model from storage classes. Those include cell, header or footer class types to gather type information and being able to return model of correct type. Again, no need for type casts.

  let post = manager.itemForCellClass(PostCell.self, atIndexPath: indexPath)
  let postHeaderModel = manager.itemForHeaderClass(PostHeaderClass.self, atSectionIndex: sectionIndex)
  let postFooterModel = manager.itemForFooterClass(PostFooterClass.self, atSectionIndex: sectionIndex)

There's also convenience getter, that will allow you to get model from visible UICollectionViewCell.

  let post = manager.itemForVisibleCell(postCell)

Error reporting

In some cases DTCollectionViewManager will not be able to create cell or supplementary view. This can happen when passed model is nil, or mapping is not set. By default, 'fatalError' method will be called and application will crash. You can improve crash logs by setting your own error handler via closure:

manager.viewFactoryErrorHandler = { error in
    // DTCollectionViewFactoryError type
    print(error.description)
}

ObjectiveC

DTCollectionViewManager is heavily relying on Swift 2 protocol extensions, generics and associated types. Enabling this stuff to work on objective-c right now is not possible. Because of this DTCollectionViewManager 4 does not support usage in objective-c. If you need to use objective-c, you can use latest compatible version of DTCollectionViewManager.

Documentation

You can view documentation online or you can install it locally using cocoadocs!

Also check out wiki page for some information on DTCollectionViewManager internals.

Running example project

pod try DTCollectionViewManager

Thanks

dtcollectionviewmanager's People

Contributors

artfeel avatar biow0lf avatar bitdeli-chef avatar dentelezhkin avatar orkenstein avatar readmecritic 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.