Delegate and Data Source of Collection Views
How I split delegate/data source and view controller of UICollectionViews.
Recently I started to split the view controller of a UICollectionView and its delegate and data source. The delegate and data source are put into the same class which is a subclass of NSObject. In the view controller the collection view is defined within loadView: (I don't like Interface Builder and therefore construct the views in code) and the delegate and data source is set:
[code language="objc" light="true"]
- (void)loadView {
CGRect frame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:frame];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
_collectionView = [[UICollectionView alloc] initWithFrame:frame
collectionViewLayout:collectionViewFlowLayout];
_collectionView.delegate = self.collectionViewDelegateAndDataSource;
_collectionView.dataSource = self.collectionViewDelegateAndDataSource;
[contentView addSubview:_collectionView];
self.view = contentView;
}
[/code]
(When using UICollectionViews one has to register the classes for the cells before any cell can be created. This is needed because within the cell creation dequeueReusableCellWithReuseIdentifier:forIndexPath: is called. This method dequeues a cell for the given identifier if possible and creates a new cell otherwise. To create a cell the collection view needs to know the class of the cell. That's why one has to register the classes for the cells. I do this normally in loadView.)
But here comes the drawback of putting the delegate/data source of the collection view into its own class:
When the delegate and data source isn't the view controller, both, the delegate/data source and the view controller need to know the classes which are used for the cells (the view controller needs to register the cells and the data source needs to populate the cells). This is not clean code because the information is doubled.
To remove this code doubling I have defined a protocol with one method
@protocol DDHRegisterCellsProtocol <NSObject> - (void)registerCellsForCollectionView:(UICollectionView*)collectionView; @end
and require the delegate/data source to conform to this protocol. With this protocol the delegate/data source can register the classes for the cells without the need of a property holding a reference to the collection view. And the view controller doesn't need to know how the cells look like and how they are created. The only thing the view controller has to do is to call the protocol method.
This looks much better.
A project demonstrating this can be found on github. In this demo you can also see how I construct user interfaces without using Interface Builder.