Recently,I am tring to restruct my code,and find out that every viewController includes a long gross code to define dataSource
and delegate
.As a result,I create CBTableViewDataSource when I was thinking how to write dataSource
in an elegant way.
Without using CBTableViewDataSource
// define a enum to split section
typedef NS_ENUM(NSInteger, SectionNameDefine) {
SECTION_ONE,
SECTION_TWO,
SECTION_THREE,
SECTION_FOUR,
//...
COUNT_OF_STORE_SECTION
};
// define identifier for section
#define IDENTIFIER_ONE @"IDENTIFIER_ONE"
#define IDENTIFIER_TWO @"IDENTIFIER_TWO"
#define IDENTIFIER_THREE @"IDENTIFIER_THREE"
#define IDENTIFIER_FOUR @"IDENTIFIER_FOUR"
//...
// register cell class for section
[self.tableView registerClass:[OneCell class] forCellWithReuseIdentifier:IDENTIFIER_ONE];
[self.tableView registerClass:[TwoCell class] forCellWithReuseIdentifier:IDENTIFIER_TWO];
[self.tableView registerClass:[ThreeCell class] forCellWithReuseIdentifier:IDENTIFIER_THREE];
[self.tableView registerClass:[FourCell class] forCellWithReuseIdentifier:IDENTIFIER_FOUR];
// implementation datasource protocol
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return COUNT_OF_STORE_SECTION;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return ((NSArray*)self.data[section]).count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = (NSUInteger) indexPath.section;
NSUInteger index = (NSUInteger) indexPath.row;
switch(section) {
case SECTION_ONE:
// to do something
return cell;
case SECTION_TWO:
// to do something
return cell;
case SECTION_THREE:
// to do something
return cell;
//...
}
return cell;
}
// ...
Using CBTableViewDataSource
CBTableViewDataSource * dataSource = CBDataSource(self.tableView)
.section()
.cell([OneCell class])
.data(self.viewModel.oneData)
.adapter(^UITableViewCell *(OneCell * cell,NSDictionary * data,NSUInteger index){
//bind data form data to cell
return cell;
})
.section()
.cell([TwoCell class])
.data(self.viewModel.twoData)
.adapter(^UITableViewCell *(TwoCell * cell,NSDictionary * data,NSUInteger index){
//bind data form data to cell
return cell;
})
// ...
.make();
CBTableViewDataSource allows us to define dataSouce
in functional programming,logical sequences and pages are order consistent.Each section starts with section()
,behind section()
,can make some configures to section。But must set up cell,data,adapter for each section.cell
is the cell class which section is using,data
is the data of section,and adapter
binds your data with the cell.At the same time,it will set the cell height of the section,or use an auto height calculation.What's more,you can also set the title,or the touch event of the cell and so on.
CBTableViewDataSource mainly solves servel problems:
1.Avoid to use all kinds of strange macro definition.The cell class and the identifier will be registed automatically. 2.A perfect solution to solve the problems of different height of calls,provides an interface to calculate the height of cell automatically. 3.An elegent API for dataSource development.
DEMO includes two pages,First Show multiple complex section usages in a page.The APP modeled a famous APP in China,mainly showed that the advantage of the framework when use to develop dataSource.
second This page use a Feed page to show the usage of autoHeight.Just need to use function autoHeight
and the calculation of the height of the cell will be solve.
The framework includes four files at all.
CBDataSourceMaker.h
CBDataSourceMaker.m
CBTableViewDataSource.h
CBTableViewDataSource.m
Download and use files from Pod directly
pod 'CBTableViewDataSource', '~> 1.0.0'
Or copy four files above into your project directly.
#import <CBTableViewDataSource/CBTableViewDataSource.h>
@property(nonatomic, retain) CBTableViewDataSource * dataSource;
_dataSource = CBDataSource(self.tableView).section()
.title(@"section one")
.cell([TestCell class])
.data(array)
.adapter(^(TestCell * cell,NSDictionary * dic,NSUInteger index){
cell.content.text = dic[@"content"];
return cell;
})
.make()
!!! Waring!!! Do not reassign dataSource directly.
//BAD
self.tableView.dataSource = CBDataSource(self.tableView)
.section()
.cell(...)
.data(...)
.adapter(...)
.make()
Because dataSource in UITableView is a weak typing,it will be freed without any strong reference after assigned。
Build a CBDataSourceMaker
object,use it to create CBTableViewDataSource
,assign a tableView
object which need to be binded with dataSource
.
Use to spilt serveral sections,section() is needed to assigned in the beginning of every section.
Give a class of cell,suck as [UITableViewCell class]
.The current section will all use this cell.And you need to know that the framework will regists and binds identifier so the cell needed not to registes.
Give an array with the data which will be showed in the page.
Adapter,use this function to binds data with cell. Parament is a block,which contains a cell object,a data object and an index. The block is allowed to be casted. Example:
adapter(^(GoodsCell * cell,GoodsModel * goods,NSUInterger index){
cell.goods = goods;
return cell;
})
Set tableHeaderView.The parament requests a Block,the block should contains an UIView。
set tableFooterView.The parament is a Block,the block requests a UIView. The extra lines will be removed in tableView when the page is empty. Example:
footerView(^(){
//Return an empty View,there is no line when the page without any content or the content is less than one page.
return [[UIView alloc]init];
})
Set a fixed height for each section separately. Two special examples:
- This function will be unavailable after using autoHeight.
- The height is public for all section if set it before all sections.
In order to calculate the height of the cell automatically,for the situation which the heights of cells are unfixed. Warning:
- If the the height of cell is fixed,please do not user autoHeight.Any dispensable calculation of autoHeight will reduce the performence.Even through that framework has been designed with a perfect cache model,we'd better make good use of any performence.
- This function only available to autolayout.
** Must set up right constrains:**
- All cells must be put into cell.contentView,else will be calculated wrongly
- SET UP RIGHT COMPLETE CONSTRAINS!!!
Make sure that a constrain should inclues two principles.
1.Any independent widget inside the cell should has a certain positon and a certain size。Such as the upper left corner is fixed on the upper left corner of the cell,set size with height and width,or set lower right corner to calculate the size when the positions of widgets are able to assign. What' more,the widget includes UILabel and UIImageView,just need to assign the size of one direction,another direction will be calculate automatically.For example, knows the width and the content of label, the height is calculatable.
2.To the cell itself,the size must be assigned.Size can be calculated by restricting its upper and lower,right and left widgets,these widgets with content should be definited positions and sizes.It is worth mentioning that it is easy to loss the restrain of the bottom.Because no exception will be raised even the cell lose a restrain of the bottom.The necessary conditions for the calculation of the height of the cell are not satisfied.
Parament requests a Block,which used to set up the click event of the cell,and 'index' is the index touch positon of the current section,'data' is the data of current click position.
Set title for each section.
Run after finished setup.