An overview of the

This article requires a good understanding of ReactiveCocoa, as well as the illustrated ReactiveCocoa basic functions

Cocoa Touch Framework is certainly a good Framework, especially for animation support, probably the best of all the frameworks I’ve worked with (although I’ve worked with a few frameworks), but there are a lot of fun points to be made about UITableView. From my perspective, Try to solve these teasing points and give the solution.

UITableView enumeration abuse

Enumerations are always meant to be extensible. The use of UITableViewStyle in UITableView is an abuse. First look at the definition of enumerations.

typedef NS_ENUM(NSInteger, UITableViewStyle) {
    UITableViewStylePlain,          // regular table view
    UITableViewStyleGrouped         // preferences style table view
};
Copy the code

UITableViewStyle wants to distinguish whether the section headers or footers are floating or not.

case plain
A plain table view. Any section headers or footers are displayed as inline separators and float when the table view is scrolled.
case grouped
A table view whose sections present distinct groups of rows. The section headers and footers do not float.
Copy the code

UITableView initialization function

- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style; // must specify style at creation. -initWithFrame: calls this with UITableViewStylePlain
Copy the code
  • The unreasonableness of UITableViewStyle as an argument to an initializer function, most UIViews and their subclasses are initializer functions of the same style, it’s a little bit weird when it comes to UITableView, the designer put UITableViewStyle in the initializer as an argument, You don’t want the style to change after the UITableView is initialized. The possible reason is that the style is changed during the sliding process of the UITableView, regardless of whether there was a floating header or footer, and the change may render the UI more obtuse, and the change may not make sense.
  • The UITableViewStyle came from all the enumerations. When an enumeration only had two options, the enumerations were often considered BOOL, which was not too bad to read.
  • UITableViewStylePlain doesn’t make sense, we know that UITableView always has sections, Plain, from its semantics and the display of its StoryBoard defaults, is probably meant to represent a situation where there is only one section, so it doesn’t really matter if the header or footer floats, If the header or footer does not need to float, it is actually a Cell, because the end result is the same. If multiple sections are required, but the header or footer does not need to float, then the header or footer is better represented as a Cell.

UITableViewStyle should not be used.

UITableViewCell enumeration is out of order

UITableViewCell has several enumerations that are used incorrectly.

UITableViewCellStyle disorderly use

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,	// Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
    UITableViewCellStyleValue1,		// Left aligned label on left and right aligned label on right with blue text (Used in Settings)
    UITableViewCellStyleValue2,		// Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
    UITableViewCellStyleSubtitle	// Left aligned label on top and left aligned label on bottom with gray text (Used in iPod).
};
Copy the code

UITableViewCell also has a UITableViewCellStyle in its initialization method, so let’s look at the code

// Designated initializer.  If the cell can be reused, you must pass in a reuse identifier.  You should use the same reuse identifier for all cells of the same form.  
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier;
Copy the code

If the designer of a UITableView thinks there are only two styles, then adding UITableViewCellStyle to the design of a UITableViewCell is a complete waste. In the same way, enumerations are never meant to be extended. UITableViewCell is the base class of cells, and extension is necessary. It is impossible for all cells to be exactly the same size as the enumerations defined in the UITableViewCellStyle.

Look at the various UITableViewCellStyle enumeration of named, is a brutal, UITableViewCellStyleValue1, UITableViewCellStyleValue2 what the hell are these oh, look at comments, “Used in Settings” and “Used in Phone/Contacts”, which makes it clear that these implementations are completely system components that use these implementations and then expose them directly as apis. Adding UITableViewCellStyle to the initializer contaminates the initializer and limits the extension. It’s always sad to write a subclass of UITableViewCell. The only thing UITableViewCellStyle does as a parameter is write a little bit more code, and then it doesn’t make any sense. The cells represented by these cell styles should have been subclassed entirely, so the use of UITableViewCellStyle is a bit of an outrage.

UITableViewCellSeparatorStyle disorderly use

typedef NS_ENUM(NSInteger, UITableViewCellSeparatorStyle) {
    UITableViewCellSeparatorStyleNone,
    UITableViewCellSeparatorStyleSingleLine,
    UITableViewCellSeparatorStyleSingleLineEtched   // This separator style is only supported for grouped style table views currently
};
Copy the code

There shouldn’t be an enumeration at all. CellSeparatorStyle is designed for different UITableViewstyles, whatever they are, Should only need isShowCellSeparatorLine such a BOOL value indicates whether need to display the borders, if it is UITableViewStyleGrouped this kind of style, one may require additional isCellSeparatorLineEtched, This makes sense if, based on the previous assumption, either the header or footer float by default.

When an enumerated various naming too weird, is actually to the existence of this enumeration to consider, so UITableViewCellSeparatorStyle is a typical use.

UITableViewCell’s use of the following enumeration is also debatable

typedef NS_ENUM(NSInteger, UITableViewCellSelectionStyle) {
    UITableViewCellSelectionStyleNone,
    UITableViewCellSelectionStyleBlue,
    UITableViewCellSelectionStyleGray,
    UITableViewCellSelectionStyleDefault NS_ENUM_AVAILABLE_IOS(7_0)
};
Copy the code

UITableViewCellSelectionStyle think said cell selected style, here is about several default values, in this way to improve Because CellSelectionStyle or can be customized, but UITableViewCellSelectionStyleDefault last UITableViewCellSelectionStyleNone in the beginning, Who is default?

typedef NS_ENUM(NSInteger, UITableViewCellFocusStyle) {
    UITableViewCellFocusStyleDefault,
    UITableViewCellFocusStyleCustom
} NS_ENUM_AVAILABLE_IOS(9_0);
Copy the code

UITableViewCellFocusStyle this enumeration of existence is just to futz around?

UITableView delegate is out of order

UITableViewDelegate UITableViewDataSource, including newly introduced UITableViewDataSourcePrefetching, this seems to be lack of the design of several delegate some design, more like to solve the problem and write code, As a basic framework, it is really not desirable.

UITableViewDelegate design weight

// Display customization

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
Copy the code

These delegate functions, all associated with Cell, header, and footer, are all concentrated in a delegate called UITableViewDelegate, and are named similarly. When a protocol is defined with too many @optional delegate functions, The design of the protocol itself is unreasonable and should be broken into smaller protocols. We should choose the corresponding protocol when necessary, instead of implementing the existing @optional delegate function. And then UITableViewDelegate, the protocol itself, all of its delegate functions are @optional, which really doesn’t make sense, because if we were designing the Cell, the header, the footer would actually be UIView, There is a common base class UICollectionReusableView for Cell, header, and footer. You should design a UIReusableView. (UICollectionReusableView is also unnecessary.) There are the following methods, which can be overridden in subclasses

- (void)willAppear;
- (void)didAppear;
- (void)willDisappear;
- (void)didDisappear
Copy the code

And you should design a UIReusableViewDelegate that includes the following delegate functions

- (void)willAppear:(UIReusableView*)reusableView;
- (void)didAppear:(UIReusableView*)reusableView;
- (void)willDisappear:(UIReusableView*)reusableView;
- (void)didDisappear:(UIReusableView*)reusableView;
Copy the code

UIReusableView has a delegate of UIReusableViewDelegate, and the six delegate functions mentioned above should actually implement UIReusableViewDelegate whenever the Cell, header, and footer need it.

In summary, the UITableViewDelegate is actually too heavy.

UITableViewDelegate responsibility mess

The following delegate functions should actually be in UITableViewDataSource. The header/footer data source should be equal to the cell data source. The header/footer data source should be equal to the cell data source. The header/footer data source should be equal to the cell data source.

// Variable height support - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section; // Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table.  // If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there. - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0); - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0); - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0); // Section header & footer information. Views are preferred over title should you decide to provide both - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; // custom view for header. will be adjusted to default or specified header height - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; // custom view for footer. will be adjusted to default or specified footer heightCopy the code

UITableViewDataSource design weight

After all that, the UITableViewDataSource should include the following functions

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section; - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section; - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section; ...Copy the code

In the same way that the UITableViewDelegate design is important, the DataSource of the Cell, header, and footer should also be separated. If necessary, the corresponding DataSource should be implemented, and an additional enumeration UIReusableViewType should be defined

typedef NS_ENUM(NSInteger, UIReusableViewType) {
    UIReusableViewTypeNone,
    UIReusableViewTypeHeader,
    UIReusableViewTypeFooter
};
Copy the code

UIReusableViewDataSource = UIReusableViewDataSource;

- (nullable NSString *)reusableView:(UIReusableView*)reusableView reusableViewType:(UIReusableViewType)reusableViewType titleInSection:(NSInteger)section;
- (nullable UIView *)reusableView:(UIReusableView*)reusableViewreusableViewType:(UIReusableViewType)reusableViewType viewInSection:(NSInteger)section;
- (CGFloat)reusableView:(UIReusableView*)reusableView reusableViewType:(UIReusableViewType)reusableViewType estimatedHeightInSection:(NSInteger)section;
Copy the code

Separate for cell, there are UITableViewCellDataSource, including commissioned function is as follows:

- (NSInteger)numberOfSections;
- (NSInteger)numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)heightForRowAtIndexPath:(NSIndexPath *)indexPath;
Copy the code

As for UITableViewDataSourcePrefetching should not appear, in order to optimize rolling frame rate, robbing Peter to pay Paul. From the developer’s point of view, the simplest thing to do is to give the entire data source, the rest should be UITableView itself to implement, the data has all, want to preload is the framework itself, reduce the dependence on developers, but also reduce API coupling, the more exposed the interface the worse.

Where is the way to reform?

In front of the ridicule, often will give self-think more reasonable design, but it does not have any use, the existing code can not be modified, then where is the way to transform? You can’t change the existing code, so you have to wrap things up as much as you can, and objective-C also provides an interesting compile-time constant, NS_UNAVAILABLE, which allows you to disable methods of the parent class at compile time, which is kind of perfect, so you can disable some class members that don’t make sense, To achieve a better encapsulation effect.

UITableView enumeration abuse resolved

UITableView can disable the enumeration-tainted initialization function, override the default initWithFrame initialization function and default style to UITableViewStyleGrouped. The reference LPDTableView class didn’t overwrite the initialization function for now. It is considered harmless at present.

UITableViewCell enumeration is a messy solution

UITableViewCell cannot disable the initialization function polluted by enumeration, because it will be called for reuse. Refer to LPDTableViewCell, choose to ignore UITableViewCellStyle, and extend all existing cellStyles into the corresponding subclasses. LPDTableViewDefaultCell, LPDTableViewValue1Cell, LPDTableViewValue2Cell, LPDTableViewSubtitleCell I’m going to keep the same names, because we’re all used to this ugliness.

UITableView delegate mess resolved

Since you can’t modify an existing UITableView, you can solve it from the other side.

How is UITableView data-driven

With the ViewModel, we can introduce a data-driven approach. When we need a DataSource for a Cell, a header, or a footer, Just call the method in LPDTableViewModelProtocl. The granularity of the interface is fine, but it may not be the most reasonable combination. The related functions are as follows:

- (nullable NSIndexPath *)indexPathForCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel;

- (nullable __kindof id<LPDTableCellViewModelProtocol>)cellViewModelFromIndexPath:(NSIndexPath *)indexPath;

- (NSInteger)sectionIndexForHeaderViewModel:(__kindof id<LPDTableHeaderFooterViewModelProtocol>)headerViewModel;

- (nullable __kindof id<LPDTableHeaderFooterViewModelProtocol>)headerViewModelFromSection:(NSInteger)sectionIndex;

- (NSInteger)sectionIndexForFooterViewModel:(__kindof id<LPDTableHeaderFooterViewModelProtocol>)footerViewModel;

- (nullable __kindof id<LPDTableHeaderFooterViewModelProtocol>)footerViewModelFromSection:(NSInteger)sectionIndex;

- (void)addCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel;

- (void)addCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel
        withRowAnimation:(UITableViewRowAnimation)animation;

- (void)addCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel toSection:(NSUInteger)sectionIndex;

- (void)addCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel
               toSection:(NSUInteger)sectionIndex
        withRowAnimation:(UITableViewRowAnimation)animation;

- (void)addCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels;

- (void)addCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
         withRowAnimation:(UITableViewRowAnimation)animation;

- (void)addCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                toSection:(NSUInteger)sectionIndex;

- (void)addCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                toSection:(NSUInteger)sectionIndex
         withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel atIndex:(NSUInteger)index;

- (void)insertCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel
                    atIndex:(NSUInteger)index
           withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel
                    atIndex:(NSUInteger)index
                  inSection:(NSUInteger)sectionIndex;

- (void)insertCellViewModel:(__kindof id<LPDTableCellViewModelProtocol>)cellViewModel
                    atIndex:(NSUInteger)index
                  inSection:(NSUInteger)sectionIndex
           withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                     atIndex:(NSUInteger)index;

- (void)insertCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                     atIndex:(NSUInteger)index
            withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                     atIndex:(NSUInteger)index
                   inSection:(NSUInteger)sectionIndex;

- (void)insertCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                     atIndex:(NSUInteger)index
               withAnimation:(UITableViewRowAnimation)animation;

- (void)insertCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                     atIndex:(NSUInteger)index
                   inSection:(NSUInteger)sectionIndex
            withRowAnimation:(UITableViewRowAnimation)animation;

- (void)reloadCellViewModelAtIndex:(NSUInteger)index inSection:(NSInteger)sectionIndex;

- (void)reloadCellViewModelAtIndex:(NSUInteger)index
                         inSection:(NSInteger)sectionIndex
                  withRowAnimation:(UITableViewRowAnimation)animation;

- (void)reloadCellViewModelsAtRange:(NSRange)range inSection:(NSInteger)sectionIndex;

- (void)reloadCellViewModelsAtRange:(NSRange)range
                          inSection:(NSInteger)sectionIndex
                   withRowAnimation:(UITableViewRowAnimation)animation;

- (void)removeLastCellViewModel;

- (void)removeLastCellViewModelWithRowAnimation:(UITableViewRowAnimation)animation;

- (void)removeLastCellViewModelFromSection:(NSUInteger)sectionIndex;

- (void)removeLastCellViewModelFromSection:(NSUInteger)sectionIndex withRowAnimation:(UITableViewRowAnimation)animation;

- (void)removeCellViewModelAtIndex:(NSUInteger)index;

- (void)removeCellViewModelAtIndex:(NSUInteger)index withRowAnimation:(UITableViewRowAnimation)animation;

- (void)removeCellViewModelAtIndex:(NSUInteger)index fromSection:(NSUInteger)sectionIndex;

- (void)removeCellViewModelAtIndex:(NSUInteger)index
                       fromSection:(NSUInteger)sectionIndex
                  withRowAnimation:(UITableViewRowAnimation)animation;

- (void)replaceCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                    fromIndex:(NSUInteger)index;

- (void)replaceCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                    fromIndex:(NSUInteger)index
             withRowAnimation:(UITableViewRowAnimation)animation;

- (void)replaceCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                    fromIndex:(NSUInteger)index
                    inSection:(NSUInteger)sectionIndex;

- (void)replaceCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                    fromIndex:(NSUInteger)index
                    inSection:(NSUInteger)sectionIndex
             withRowAnimation:(UITableViewRowAnimation)animation;

- (void)addSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel;

- (void)addSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel
           withRowAnimation:(UITableViewRowAnimation)animation;

- (void)addSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel
         withCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels;

- (void)addSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel
         withCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
           withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel atIndex:(NSUInteger)index;

- (void)insertSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel
                       atIndex:(NSUInteger)index
              withRowAnimation:(UITableViewRowAnimation)animation;

- (void)insertSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel
            withCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                       atIndex:(NSUInteger)index;

- (void)insertSectionViewModel:(id<LPDTableSectionViewModelProtocol>)sectionViewModel
            withCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                       atIndex:(NSUInteger)index
              withRowAnimation:(UITableViewRowAnimation)animation;

- (void)reloadSectionAtIndex:(NSUInteger)index;

- (void)reloadSectionAtIndex:(NSUInteger)index withRowAnimation:(UITableViewRowAnimation)animation;

- (void)reloadSectionsAtRange:(NSRange)range;

- (void)reloadSectionsAtRange:(NSRange)range withRowAnimation:(UITableViewRowAnimation)animation;

- (void)removeSectionAtIndex:(NSUInteger)index;

- (void)removeAllSections;

- (void)removeSectionAtIndex:(NSUInteger)index withRowAnimation:(UITableViewRowAnimation)animation;

- (void)removeAllSectionsWithRowAnimation:(UITableViewRowAnimation)animation;

- (void)replaceSectionWithCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels;

- (void)replaceSectionWithCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                        withRowAnimation:(UITableViewRowAnimation)animation;

- (void)replaceSectionWithCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                               atSection:(NSUInteger)sectionIndex;

- (void)replaceSectionWithCellViewModels:(NSArray<__kindof id<LPDTableCellViewModelProtocol>> *)cellViewModels
                               atSection:(NSUInteger)sectionIndex
                        withRowAnimation:(UITableViewRowAnimation)animation;
Copy the code

UITableView delegate to RACSignal

Introduce RACSignal in ReactiveCocoa and convert all the delegate functions in UITableViewDelegate into signals. When we need to implement a certain delegate function, we just need to subscribe to the corresponding RACSignal, and there are no side effects.

@property (nonatomic, strong, readonly) RACSignal *willDisplayCellSignal;
@property (nonatomic, strong, readonly) RACSignal *willDisplayHeaderViewSignal;
@property (nonatomic, strong, readonly) RACSignal *willDisplayFooterViewSignal;
@property (nonatomic, strong, readonly) RACSignal *didEndDisplayingCellSignal;
@property (nonatomic, strong, readonly) RACSignal *didEndDisplayingHeaderViewSignal;
@property (nonatomic, strong, readonly) RACSignal *didEndDisplayingFooterViewSignal;
@property (nonatomic, strong, readonly) RACSignal *didHighlightRowAtIndexPathSignal;
@property (nonatomic, strong, readonly) RACSignal *didUnhighlightRowAtIndexPathSignal;
@property (nonatomic, strong, readonly) RACSignal *didSelectRowAtIndexPathSignal;
@property (nonatomic, strong, readonly) RACSignal *didDeselectRowAtIndexPathSignal;
@property (nonatomic, strong, readonly) RACSignal *willBeginEditingRowAtIndexPathSignal;
@property (nonatomic, strong, readonly) RACSignal *didEndEditingRowAtIndexPathSignal;
Copy the code

There are viewModels for Cell, header, and footer

The Cell, header, and heel viewModels must be named according to the convention so that they will automatically match. In addition, Cell, header, and footer are all reused by default, just like the same type of reuseIdentifier. Functions related to reuse are in LPDTableViewFactory. In this class, when we care about the DataSource or Delegate, we simply interact with the corresponding ViewModel, uncoupling the Cell, header, and footer.

LPDTableSectionViewModelProtocol

The protocol implementation class LPDTableSectionViewModel, only abstracted in the ViewModel layer, so as to improve the implementation of the ViewModel layer, there is no corresponding SectionView.

About the height

BindingTo: ViewModel = bindingTo:viewModel = bindingTo: ViewModel = bindingTo: ViewModel = bindingTo: ViewModel

After the transformation of the example

Load the tableView’s data

-(void)reloadTable { if (self.datas && self.datas.count > 0) { NSMutableArray *cellViewModels = [NSMutableArray array]; for (LPDPostModel *model in self.datas) { LPDTablePostCellViewModel *cellViewModel = [[LPDTablePostCellViewModel alloc]initWithViewModel:self.tableViewModel]; cellViewModel.model = model; [cellViewModels addObject:cellViewModel]; } [self.tableViewModel replaceSectionWithCellViewModels:cellViewModels withRowAnimation:UITableViewRowAnimationTop]; }else{ [self.tableViewModel removeAllSections]; }}Copy the code

Add a cell

        LPDPostModel *model = [[LPDPostModel alloc]init];
        model.userId = 111111;
        model.identifier = 1003131;
        model.title = @"First Chapter";
        model.body = @"GitBook allows you to organize your book into chapters, each chapter is stored in a separate file like this one.";
        LPDTablePostCellViewModel *cellViewModel = [[LPDTablePostCellViewModel alloc]initWithViewModel:self.tableViewModel];
        cellViewModel.model = model;
        [self.tableViewModel insertCellViewModel:cellViewModel atIndex:0 withRowAnimation:UITableViewRowAnimationLeft];
Copy the code

Adding Cells in Batches

NSMutableArray *cellViewModels = [NSMutableArray array]; LPDTableDefaultCellViewModel *cellViewModel1 = [[LPDTableDefaultCellViewModel alloc] initWithViewModel:self.tableViewModel]; Cellviewmodel1.text = @" Finland cannot "; Cellviewmodel1.detail = @" Royal jelly sent "; cellViewModel1.image = [UIImage imageNamed:@"01"]; [cellViewModels addObject:cellViewModel1]; LPDTableValue1CellViewModel *cellViewModel2 = [[LPDTableValue1CellViewModel alloc] initWithViewModel:self.tableViewModel]; Cellviewmodel2. text = @" Finland cannot "; Cellviewmodel2.detail = @" Royal jelly sent "; cellViewModel2.image = [UIImage imageNamed:@"02"]; [cellViewModels addObject:cellViewModel2]; LPDTableValue2CellViewModel *cellViewModel3 = [[LPDTableValue2CellViewModel alloc] initWithViewModel:self.tableViewModel]; Cellviewmodel3. text = @" Finland cannot "; Cellviewmodel3. detail = @" Royal jelly sent "; [cellViewModels addObject:cellViewModel3]; LPDTableSubtitleCellViewModel *cellViewModel4 = [[LPDTableSubtitleCellViewModel alloc] initWithViewModel:self.tableViewModel]; Cellviewmodel4.text = @" Finland cannot "; Cellviewmodel4.detail = @" Royal jelly sent "; cellViewModel4.image = [UIImage imageNamed:@"03"]; [cellViewModels addObject:cellViewModel4]; [self.tableViewModel insertCellViewModels:cellViewModels atIndex:0 withRowAnimation:UITableViewRowAnimationLeft];Copy the code

Delete a Cell

        [self.tableViewModel removeCellViewModelAtIndex:0 withRowAnimation:UITableViewRowAnimationRight];
Copy the code

The Cell didSelectRowAtIndexPathSignal

[[[self.waybillsTableViewModel.didSelectRowAtIndexPathSignal deliverOnMainThread] takeUntil:[self rac_willDeallocSignal]] subscribeNext:^(RACTuple *tuple) { @strongify(self);  __kindof id<LPDTableCellViewModelProtocol> cellViewModel = tuple.second;  LPDWaybillModel *waybillModel = cellViewModel.model;  if (waybillModel.cancelCode == 0) { LPDWaybillDetailViewModel *detailViewModel = [[LPDWaybillDetailViewModel alloc] init]; detailViewModel.waybillId = waybillModel.waybillId; [self.navigation pushViewModel:detailViewModel animated:YES]; }}];Copy the code

Please download lpd-TableView-kit and take a look at the demo.

Please correct any intellectual property rights, copyright issues or theoretical errors.

Please indicate the original author and above information.