Datasource magic of IOS development, elegant writing let you easily control tableview

Time:2020-10-24

brief introduction

Recently, when refactoring the code written before, I found that there is a stinky and long code in each viewcontroller to define thedataSourceanddelegateSo I wonder if there is a more elegant way to writedataSourceThe cbtableviewdatasource is generated.

Project address: https://github.com/cocbin/CBTableViewDataSource

Before 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;
}
// ...

After 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 datasources in a functional way, in the same logical order as the page is rendered.
Each section starts with section (). After section (), you can configure the section, and require each section to set cell, data, and adapter. Cell represents the cell class used by the section, data represents the data of the section, and adapter is used to bind the data to the cell. At the same time, you can configure the height of the cell in the section, or set the automatic calculation height. You can also set the section title, cell click events, and so on.

Cbtableviewdatasource mainly solves the following problems:

  1. Avoid writing all kinds of messy macro definition, automatically register cell class and set identifier automatically.

  2. It provides a set of perfect solution to the calculation problem of different cell height, and provides the interface of automatic calculation of cell height.

  3. Provides a set of elegant API, very elegant and logical writing datasource.

Interpretation of demo

Demo consists of two pages,FirstThis paper shows the usage of complex multi section pages. By imitating the home page of various popular apps on the market, it shows the advantages of the framework in writing datasource clearly, and the logical order is completely consistent with the order of page presentation.
Datasource magic of IOS development, elegant writing let you easily control tableview
Datasource magic of IOS development, elegant writing let you easily control tableview

secondThe page shows the usage of autoheight through a feed page. Just callautoHeightFunction, one sentence to solve the problem of cell height calculation.

Datasource magic of IOS development, elegant writing let you easily control tableview

usage

Install

The framework consists of four documents

CBDataSourceMaker.h
CBDataSourceMaker.m

CBTableViewDataSource.h
CBTableViewDataSource.m

It can be downloaded and used directly through pod

pod 'CBTableViewDataSource', '~> 1.0.0'

Or directly copy the above four files into your project.

Import

#import <CBTableViewDataSource/CBTableViewDataSource.h>

statement

@property(nonatomic, retain) CBTableViewDataSource *  dataSource;

initialization

_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()

!!! be careful!!!
Datasource cannot be assigned directly

//BAD
self.tableView.dataSource = CBDataSource(self.tableView)
    .section()
    .cell(...)
    .data(...)
    .adapter(...)
    .make()

Because the datasource of uitableview declares weak, its memory will be released directly because there is no strong reference after assignment.

API

CBDataSource(UITableView * tableView)

Create aCBDataSourceMakerObject for creatingCBTableViewDataSource, pass in one that needs to be bound to thedataSourceOftableViewobject

section()

Used to split multiple sections from the beginning of each section to the beginning of a section to be declared with section()

cell(Class cell)

Pass in the class of a cell, such as[UITableViewCell class]
This indicates that the current section uses this cell. Note that the cell does not need to be registered. The framework will automatically register and bind the identifier

data(NSArray * data)

Pass in an array representing the data to be rendered on the interface

adapter(^(id cell,id data,NSUInteger index))

Adapter, which is used to bind the data to the cell.
The parameter is a block, which will pass a cell object, a data object and an index.
You can cast parameter types directly on the block.
For example:

adapter(^(GoodsCell * cell,GoodsModel * goods,NSUInterger index){
    cell.goods = goods;
    return cell;
})

headerView(UIView*(^)())

Set tableheaderview
The parameter is a block, which requires a uiview to be returned.

footerView(UIView*(^)())

Set tablefooterview
The parameter is a block, which requires a uiview to be returned.
It is often used to remove extra underscores when the page is blank.
For example:

footerView(^(){
    //Returns a blank view so that no extra lines appear when the page has no content or less than one page.
    return [[UIView alloc]init];
})

height(CGFloat * height)

Set a fixed height for each section individually.
There are two exceptions:

  • When autoheight is used, this setting will not work

  • When the height is set before all sections, the height is common to all sections

autoHeight()

The cell height is calculated automatically, which is used when the cell height is not fixed.

be careful:

  • When the height of the cell is fixed, please do not use autoheight, because the calculation height of autoheight will consume certain performance. Although the framework has done a very perfect cache processing for height computing, the pursuit of high performance must be improved.

  • This setting only applies toAutoLayout is valid

The constraints must be set correctly

  • All components in the cell must be placed in the cell.contentView Inside, otherwise it will be miscalculated

  • There must be complete constraints.

There are two principles for determining whether a constraint is complete

  1. For each independent control inside the cell, the position and size can be determined. For example, the upper left corner is set at the upper left corner of the cell, and then the height and width are set to determine the size, or the lower right corner is set to determine the size. The premise is that the component relative to the lower right corner can determine the position. In addition, uilabel and uiimageview, which contain content, only need to determine the size of one direction, and it will have more content. For example, if the label knows the width and content, it can calculate the height.

  2. For the cell itself, it must be possible to determine its size. Dimensions are calculated by constraining the controls above, below, left, and right, so the controls that constrain its bottom and right must be able to determine the position and size. It is worth saying that it is easy to omit the bottom constraint here, because even if the cell has no bottom constraint, it will not report an error, but it cannot meet the necessary conditions for calculating the cell height.

event(^(NSUInteger index,id data))

The parameter requires a block to set the click event of the cell. Index indicates the index position of the current section and data represents the data of the current click position.

title(NSString* title)

Used to set the title of each section.

make()

After the setting is completed, it means that the setting has been completed.

Recommended Today

Explain module, import and export in JavaScript

Author: Tania rascia Crazy technology house Original text:https://www.taniarascia.com/j… In the era of the Internet, websites are mainly developed with HTML and CSS. If you load JavaScript into a page, it usually provides effects and interactions in the form of small fragments. Generally, all JavaScript code is written in a file and loaded into a filescriptTag. […]