 
 import UIKit
 
+public protocol CollectionViewModelControllerDelegate: class {
+    func cell(forIdentifier identifier: String) -> CollectionCell
+    func update(_ cell: UICollectionViewCell & CollectionViewModelCell, at indexPath: IndexPath)
+}
+
+public extension CollectionViewModelControllerDelegate where Self: CollectionViewModelController {
+    func cell(forIdentifier identifier: String) -> CollectionCell {
+        return .empty
+    }
+    func update(_ cell: UICollectionViewCell & CollectionViewModelCell, at indexPath: IndexPath) {
+        let item = dataSource.item(at: indexPath)
+        cell.update(with: item)
+    }
+}
+
 open class CollectionViewModelController: UICollectionViewController {
     
     // MARK: Properties
+
+    public weak var delegate: CollectionViewModelControllerDelegate?
 
     open var isAutomaticReloadEnabled = true
 

    open override func viewDidLoad() {
        super.viewDidLoad()
        
        registerCells()
    }
    
    // MARK: Abstract
    
    open func cell(forIdentifier identifier: String) -> CollectionCell {
        return .empty
    }
    
    open func update(_ cell: UICollectionViewCell & CollectionViewModelCell, at indexPath: IndexPath) {
        let item = dataSource.item(at: indexPath)
        cell.update(with: item)
    }
    
    // MARK: Helpers
    
    private func reload() {
        if Thread.isMainThread {
            registerCellsAndReloadDataIfNeeded()
        } else {
            DispatchQueue.main.async { [weak self] in
                self?.registerCellsAndReloadDataIfNeeded()
            }
        }
    }
    
    private func registerCellsAndReloadDataIfNeeded() {
        registerCells()
        collectionView?.reloadData()
    }
    
    private func registerCells() {

    }
    
    private func registerCell(with identifier: String) {
        guard let delegate = delegate else {
            return
        }
        switch delegate.cell(forIdentifier: identifier) {
        case .empty:
            collectionView?.register(CollectionCellEmpty.self, forCellWithReuseIdentifier: identifier)
        case .customClass(let cellClass):
