/GPJDataDrivenTableView

The data-driven way to use UITableView

Primary LanguageObjective-CMIT LicenseMIT

GPJDataDrivenTableView

Description

GPJDataDrivenTableView is a data-driven way to use UITableView.

GPJDataDrivenTableView has the following features:

  • two-way data binding (mapping)
    • bind UI element XXXCell on XXXData based on their class name
    • send action from XXXCell to XXXData through GPJTableViewData.didSelectAction block
  • the interface is intuitive, so it easy to use
    • construct dataArray with various subclasses of GPJTableViewData
    • feed the dataArray to -[GPJDataDrivenTableView reloadDataArray:]

GPJDataDrivenTableView has the following advantages:

  • decouple code by cell type, so we gain very fine granularity code decoupling
    • XXXCell and XXXData resides in XXXData.h/.m
    • YYYCell and YYYData resides in YYYData.h/.m
  • there is NOT IndexPath in business code, so it eliminates errors around index

Then, we can add/delete/modify cell independently:

  • addding a new kind of cell or a new cell instance will NOT affect others
  • deleting a kind of cell or a cell instance will NOT affect others
  • modifing a kind of cell or a cell instance will NOT affect others

Finally, our code can evolve with change of requirements harmoniously. 🎉🎉🎉Woohoo🎉🎉🎉

Usage

#import <GPJDataDrivenTableView/GPJDataDrivenTableView.h>

GPJDataDrivenTableView *dataDrivenTableView = [[GPJDataDrivenTableView alloc] initWithFrame:self.view.bounds];
dataDrivenTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:dataDrivenTableView];

NSMutableArray *dataArray = [NSMutableArray array];
{
	ActionData *actionData = [ActionData new];
	actionData.didSelectAction = ^(id data) {
	    [weakSelf actionCellReloadAction:data];
	};
	[dataArray addObject:actionData];
}
{
	ColorData *data = [ColorData new];
	data.didSelectAction = ^(id data) {
	    [weakSelf colorCellAction:data];
	};
	[dataArray addObject:data];
}
[dataDrivenTableView reloadDataArray:dataArray];

Requirements

GPJDataDrivenTableView works on iOS 6+ and requires ARC to build.

Installation

CocoaPods

pod 'GPJDataDrivenTableView'

Manual

  1. download the GPJDataDrivenTableView repository
  2. copy the GPJDataDrivenTableView sub-folder into your Xcode project

Example

screenshot_basic_small

screenshot_flex_1_small screenshot_flex_2_small screenshot_flex_3_small screenshot_flex_4_small

screenshot_edit_1_small screenshot_edit_2_small screenshot_edit_3_small screenshot_edit_4_small

Origin

The traditional way is index-driven, we implement the UITableViewDataSource's or UITableViewDelegate's methods base on indexPath:

  • -tableView:cellForRowAtIndexPath:
  • -tableView:heightForRowAtIndexPath:
  • -tableView:didSelectRowAtIndexPath:

This index-driven way based on indexPath results a lot of if-else code segments, Various cells' code mix together. it is error-prone, hard to evolve with change of requirements.

uitableview_indexdriven

The new way is data-driven. GPJDataDrivenTableView set itself as UITableView's dataSource and delegate, and mapping indexPath to data in its dataArray properly and safely. we only need construct dataArray and call reloadDataArray:, that is it.

  • construct dataArray with various subclasses of GPJTableViewData
  • feed the dataArray to -[GPJDataDrivenTableView reloadDataArray:]

uitableview_datadriven

Using data-driven way, we don't need concern about indexPath. it is error-free, it is friendly to evolve with change of requirements.

Implementation Choices and Details

After comparing the composite, subclass, category implementation, I choose the subclass imeplementation.

There are three classes: GPJDataDrivenTableView, GPJTableViewCell, and GPJTableViewData

  • GPJDataDrivenTableView: subclass of UITableView
    • it implements UITableViewDataSource and UITableViewDelegate
    • it has a dataArray property to hold instances of GPJTableViewData's subclasses
    • it binds XXXCell on XXXData using name string substitution
    • it responds tableView:didSelectRowAtIndexPath: and call GPJTableViewData.didSelectAction block
    • it hides dataSource / delegate to prevent error-usage
    • it exposes gpjDataSource / gpjDelegate for extension and customization
  • GPJTableViewCell: subclass of UITableViewCell, implement cell UI
  • GPJTableViewData: subclass of NSObject, implement -cellHeight method to specify cell height.

The code base is only about two hundreds lines, go ahead to have a look. GPJDataDrivenTableView.m

Hope you enjoy it.