Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend UICollectionViewDataSource Protocol to add default implementations

I have a fairly big application which has a lot of collection views. Most of the collection view have same implementations for Data Source and the Flow Layout Delegate (same sizes, margins etc). I am trying to create a single protocol which provides the default implementations of UICollectionViewDataSource and UICollectionViewDelegateFlowLayout. Here is my code.

protocol TiledCollectionView{}

extension UICollectionViewDataSource where Self: TiledCollectionView{
    //default implementation of the 3 methods to load the data ...
}
extension UICollectionViewDelegateFlowLayout where Self: TiledCollectionView {
    //default implementation for layout methods to set default margins etc...
}

class MyViewController: UIViewController, TiledCollectionView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
    // the rest of the required logic for view controller
    // here I Don't implement any CollectionView methods since I have provided the default implementation already
}

The problem is that, the compiler complains that MyViewController does not conform to UICollectionViewDataSource. This should not be the case because I am clearly saying that add the default implementations if the type is TiledCollectionView.

Can some one help?

like image 685
drcocoa Avatar asked Oct 08 '15 09:10

drcocoa


3 Answers

I know it's not exactly what you asked, I tried - it didn't work. Now looking for possible answer, because had similiar situation. But I can offer you such on option how to hide in your custom protocol all the logic for delegate/dataSource implementation.

class CollectionViewProtocolHandler: NSObject, UICollectionViewDelegate, UICollectionViewDataSource  {

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 0
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        return UICollectionViewCell() // only for test
    }
}

protocol CollectionViewProtocol {
    var handler: CollectionViewProtocolHandler! {get set}
    mutating func useProtocolForCollectionView(collectionView: UICollectionView)
}

extension CollectionViewProtocol {
    mutating func useProtocolForCollectionView(collectionView: UICollectionView) {
        handler = CollectionViewProtocolHandler()
        collectionView.delegate = handler
        collectionView.dataSource = handler
    }
}

class ViewController: UIViewController, CollectionViewProtocol {
    var handler: CollectionViewProtocolHandler! // CollectionViewProtocol convenience

    override func viewDidLoad() {
        super.viewDidLoad()

        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: UICollectionViewFlowLayout())
        collectionView.backgroundColor = .redColor()
        view.addSubview(collectionView)
        var reference = self
        reference.useProtocolForCollectionView(collectionView) // for initialize protocol
    }
}
like image 55
katleta3000 Avatar answered Oct 16 '22 13:10

katleta3000


I expect the problem is that this is an Objective-C protocol. Objective-C has never heard of a protocol extension. Therefore it has no knowledge that this protocol extension is injecting two functions into MyClass. It can't see them, and so as far as it is concerned, the protocol requirements are not satisfied.

like image 24
Arsen Avatar answered Oct 16 '22 12:10

Arsen


To add to, but modify, what katleta3000 answered with, you can restrict a protocol to only apply to a 'class'

CollectionViewProtocol : class

so that you don't need 'useProtocolForCollectionView:' to be mutating

Which then makes it so you don't need that var reference = self and you can just say self.userProtocolForCollectionView(collectionView)

Especially if you only plan on implementing this protocol only with NSObject's or class types (UIViewController, UICollectionView, etc.)

like image 1
Cory Wilhite Avatar answered Oct 16 '22 13:10

Cory Wilhite