閱讀本文須要對ReactiveCocoa足夠了解,也能夠參閱圖解ReactiveCocoa基本函數git
Cocoa Touch Framework無疑是一個很好的框架,特別是對動畫的支持,在我接觸過的框架中多是最好的(固然我接觸的框架可能比較少),可是就UITableView來講確實存在不少吐槽點,從我我的理解的角度作些分析,嘗試去解決這些吐槽點,並給到的解決方案。github
枚舉歷來都是爲了可擴展而存在的,UITableView中對UITableViewStyle的使用堪稱濫用,先看看這個枚舉的定義,枚舉項的命名不夠直觀,源碼的註釋也得不到有效信息,objective-c
typedef NS_ENUM(NSInteger, UITableViewStyle) {
UITableViewStylePlain, // regular table view
UITableViewStyleGrouped // preferences style table view
};
複製代碼
再看看以下文檔的說明,基本明確了設計者的本意,UITableViewStyle想要區分的是頁眉或頁腳(section headers or footers)是否浮動,接下來作個剖析:api
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.
複製代碼
UITableView的初始化函數緩存
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style; // must specify style at creation. -initWithFrame: calls this with UITableViewStylePlain
複製代碼
綜上得出結論:UITableViewStyle是不應用。bash
UITableViewCell存在好幾個枚舉的亂用,亂用表示不應用的時候用了。app
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).
};
複製代碼
UITableViewCell的初始化方法中一樣也帶上了UITableViewCellStyle,先看代碼框架
// 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;
複製代碼
若是說UITableView設計者以爲就只存在兩種style,那麼UITableViewCell設計中加入UITableViewCellStyle就顯得徹底是亂用了。同樣的道理,枚舉歷來就不是爲了擴展而存在,UITableViewCell作爲cell的基類,擴展是必須的,不可能全部的cell都長的跟UITableViewCellStyle中定義的幾個枚舉項所分類的徹底同樣,因此這個設計是有多噁心啊。ide
再看看UITableViewCellStyle的各個枚舉項的命名,簡直是殘暴啊,UITableViewCellStyleValue1,UITableViewCellStyleValue2這些是什麼鬼哦,再看看註釋,分別說明Used in Settings和Used in Phone/Contacts,這就很明顯了,這些實現徹底就是系統組件用到了這樣的實現,而後直接作爲api開放出來的,並無作很好的抽象,在初始化函數中加入UITableViewCellStyle,污染了初始化函數,限制了擴展,往往在寫一個UITableViewCell的子類時,老是有一種莫名的哀傷,UITableViewCellStyle作爲參數存在惟一的做用就是多寫了點代碼,而後沒有任何意義。這些cell style所表示的cell徹底應該經過子類化來實現的,因此UITableViewCellStyle的亂用是有點慘不忍睹的。函數
typedef NS_ENUM(NSInteger, UITableViewCellSeparatorStyle) {
UITableViewCellSeparatorStyleNone,
UITableViewCellSeparatorStyleSingleLine,
UITableViewCellSeparatorStyleSingleLineEtched // This separator style is only supported for grouped style table views currently
};
複製代碼
怎麼說也不該該存在這樣一個枚舉,CellSeparatorStyle這裏針對不一樣的UITableViewStyle而設計的,不論是何種style,應該只須要isShowCellSeparatorLine這樣一個BOOL值表示是否須要顯示邊框,若是是UITableViewStyleGrouped這種style,可能須要額外的一個isCellSeparatorLineEtched,若是根據前面的假設,頁眉或頁腳都是默認浮動的話,這樣設計是很合理的。
當一個枚舉各項的命名過於詭異時,這個枚舉的存在其實是要好好考慮下的,因此UITableViewCellSeparatorStyle也是典型的亂用。
typedef NS_ENUM(NSInteger, UITableViewCellSelectionStyle) {
UITableViewCellSelectionStyleNone,
UITableViewCellSelectionStyleBlue,
UITableViewCellSelectionStyleGray,
UITableViewCellSelectionStyleDefault NS_ENUM_AVAILABLE_IOS(7_0)
};
複製代碼
UITableViewCellSelectionStyle想表示cell選中的樣式,這裏大概是經過這種方式來提升幾種默認值,由於CellSelectionStyle仍是能夠定製的,可是UITableViewCellSelectionStyleDefault放在最後UITableViewCellSelectionStyleNone放在最開始,到底誰是default哦;
typedef NS_ENUM(NSInteger, UITableViewCellFocusStyle) {
UITableViewCellFocusStyleDefault,
UITableViewCellFocusStyleCustom
} NS_ENUM_AVAILABLE_IOS(9_0);
複製代碼
UITableViewCellFocusStyle這個枚舉的存在難道僅僅是爲了無病呻吟嗎?
UITableViewDelegate,UITableViewDataSource,包括剛引入的UITableViewDataSourcePrefetching,這幾個delegate的設計好像是缺乏了些設計,更像是爲了解決問題而寫代碼,做爲一個基礎框架,實在是不可取的。
// 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);
複製代碼
這幾個委託函數,都是與Cell、頁眉、頁腳相關的,可是全都集中在UITableViewDelegate這個委託中,且命名都是相似,當一個protocol在定義時存在過多的@optional委託函數時,這個protocol的設計自己就是不合理的,應該拆分紅更細的protocol,咱們應該時在必要的時候選擇相應的protocol,而不是實現存在的@optional委託函數,而後UITableViewDelegate這個protocol自己全部的委託函數都是@optional,這是真的不合理,若是是咱們來設計Cell、頁眉、頁腳實際上都是應該UIView,且存在諸多共同點(參考UICollectionView的設計,Cell、頁眉、頁腳就存在一個共同的基類UICollectionReusableView),應該設計一個UIReusableView,(UICollectionReusableView也能夠不須要了)其中存在以下方法,這些方法能夠在子類中重寫
- (void)willAppear;
- (void)didAppear;
- (void)willDisappear;
- (void)didDisappear
複製代碼
且應該設計一個UIReusableViewDelegate,其包括以下委託函數
- (void)willAppear:(UIReusableView*)reusableView;
- (void)didAppear:(UIReusableView*)reusableView;
- (void)willDisappear:(UIReusableView*)reusableView;
- (void)didDisappear:(UIReusableView*)reusableView;
複製代碼
UIReusableView存在UIReusableViewDelegate的一個delegate,前面所提到的那六個委託函數,實際上應該在Cell、頁眉、頁腳各自須要的時候實現UIReusableViewDelegate。
綜上,UITableViewDelegate其實是過重了。
下面這些委託函數,實際上應該存在UITableViewDataSource中。頁眉、頁腳的數據源跟cell的數據源應該是平等的存在,不該該是說不經常使用了,我就放到UITableViewDelegate中,原本就應該放在UITableViewDataSource,沒必要須用的能夠optional修飾下也還說得過去。
// 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 height
複製代碼
通過前面的梳理,那麼UITableViewDataSource中應該包括如下這些函數
- (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;
……
複製代碼
跟前面提到UITableViewDelegate設計之重一個道理,Cell、頁眉、頁腳的DataSource也是應該分開的,在須要的時候實現對應的DataSource,須要定義額外的一個枚舉UIReusableViewType
typedef NS_ENUM(NSInteger, UIReusableViewType) {
UIReusableViewTypeNone,
UIReusableViewTypeHeader,
UIReusableViewTypeFooter
};
複製代碼
而後對頁眉、頁腳就有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;
複製代碼
單獨的針對cell,有UITableViewCellDataSource,其中的委託函數以下:
- (NSInteger)numberOfSections;
- (NSInteger)numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)heightForRowAtIndexPath:(NSIndexPath *)indexPath;
複製代碼
至於UITableViewDataSourcePrefetching就不該該出現,爲了優化滾動幀率,拆東牆補西牆之舉。從開發者的角度,最簡單的作法就是把整個的數據源給到,剩下的就應該是UITableView自身去實現了,數據都有了,想要什麼預加載都是框架自身的事情了,減小對開發者的依賴,更是減小api的耦合度,對外暴露的接口越多越很差。
前面在吐槽的時候,往往會給出自認爲更合理的設計,然而並無什麼卵用,既有代碼是沒法修改的,那改造之路又在何方呢?不能改變既有代碼,那麼只能是將這麼東西儘量的封裝起來,Objective-C語言還提供了一個蠻有意思的編譯期常量NS_UNAVAILABLE,能夠在編譯期禁用父類的方法,算是不完美中的徹底吧,咱們能夠禁用掉一些不合理的類成員,來達到一個比較好的封裝效果。
UITableView能夠禁用被枚舉污染的初始化函數,重寫默認的initWithFrame初始化函數並默認設style爲UITableViewStyleGrouped,參考類 LPDTableView暫時並無重寫初始化函數,目前認爲無傷大雅。
UITableViewCell沒法禁用被枚舉污染的初始化函數,由於重用時會調用到,參考類 LPDTableViewCell,選擇無視UITableViewCellStyle,並將已存在的幾種cellStyle都擴展成對應的子類,LPDTableViewDefaultCell,LPDTableViewValue1Cell,LPDTableViewValue2Cell,LPDTableViewSubtitleCell命名仍是保留一致,畢竟你們都已經習慣了這種醜。
既然沒法改造既有的UITableView,能夠從另一個側面來解決。
引入MVVM的思想,爲UITableView添加對應的ViewModel,有了ViewModel,則能夠引入數據驅動的方式,當咱們須要爲Cell、頁眉、頁腳提供DataSource時,只須要調用LPDTableViewModelProtocl中的方法就行了,接口的粒度已經比較細了,但可能不是最合理的組合,相關的函數都在下面:
- (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;
複製代碼
引入ReactiveCocoa中的RACSignal,將UITableViewDelegate中的委函數都轉成信號,當咱們須要實現某一個委託函數,只須要訂閱對應的RACSignal便可,不訂閱沒有任何反作用。
@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;
複製代碼
Cell、頁眉、頁腳跟其ViewModel之間須要遵照約定好的命名規則,如此會自動匹配。另外Cell、頁眉、頁腳默認都是重用的,同一類型reuseIdentifier同樣,重用相關的函數就都在 LPDTableViewFactory。這個類中了當咱們關心DataSource或者Delegate時,咱們只須要跟對應的ViewModel交互便可,將Cell、頁眉、頁腳解耦合。
這個protocol的實現類LPDTableSectionViewModel,只是在ViewModel層抽象出來,這樣纔好完善ViewModel層的實現,並不存在對應的SectionView。
cell,header,footer的viewmodel中都有對應的height字段,須要根據viewmodel的model字段在bindingTo:viewModel函數中設置height值,能夠針對model作height的緩存。
-(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];
}
}
複製代碼
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];
複製代碼
NSMutableArray *cellViewModels = [NSMutableArray array];
LPDTableDefaultCellViewModel *cellViewModel1 =
[[LPDTableDefaultCellViewModel alloc] initWithViewModel:self.tableViewModel];
cellViewModel1.text = @"芬蘭沒法";
cellViewModel1.detail = @"蜂王漿發了";
cellViewModel1.image = [UIImage imageNamed:@"01"];
[cellViewModels addObject:cellViewModel1];
LPDTableValue1CellViewModel *cellViewModel2 =
[[LPDTableValue1CellViewModel alloc] initWithViewModel:self.tableViewModel];
cellViewModel2.text = @"芬蘭沒法";
cellViewModel2.detail = @"蜂王漿發了";
cellViewModel2.image = [UIImage imageNamed:@"02"];
[cellViewModels addObject:cellViewModel2];
LPDTableValue2CellViewModel *cellViewModel3 =
[[LPDTableValue2CellViewModel alloc] initWithViewModel:self.tableViewModel];
cellViewModel3.text = @"芬蘭沒法";
cellViewModel3.detail = @"蜂王漿發了";
[cellViewModels addObject:cellViewModel3];
LPDTableSubtitleCellViewModel *cellViewModel4 =
[[LPDTableSubtitleCellViewModel alloc] initWithViewModel:self.tableViewModel];
cellViewModel4.text = @"芬蘭沒法";
cellViewModel4.detail = @"蜂王漿發了";
cellViewModel4.image = [UIImage imageNamed:@"03"];
[cellViewModels addObject:cellViewModel4];
[self.tableViewModel insertCellViewModels:cellViewModels atIndex:0 withRowAnimation:UITableViewRowAnimationLeft];
複製代碼
[self.tableViewModel removeCellViewModelAtIndex:0 withRowAnimation:UITableViewRowAnimationRight];
複製代碼
[[[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];
}
}];
複製代碼
具體請下載lpd-tableview-kit,看看其中的demo。
若有任何知識產權、版權問題或理論錯誤,還請指正。
轉載請註明原做者及以上信息。