為何要輕量級
通常,項目中有些 viewControllers 非常臃腫,把一些控制器不需要知道的代碼和邏輯全都放在了控制器的文件中,小則好幾百行大則上千,代碼風(fēng)格飄忽不定,前邏輯后數(shù)據(jù)處理,讓擦屁股的人苦不堪言,"尼瑪,這都是什么玩意兒!!!".今天我們來研究如何把這些代碼搬到合適的位置,讓你的 viewControllers 從此告別"脂肪",挺起雙峰.
如何變得輕量級
1. 剝?nèi)?UITableViewDataSource 代理方法
項目中很多地方會用到 tableView 來展示數(shù)據(jù), 同樣 viewController 會實現(xiàn) UITableViewDataSource 的以下代理方法
- (id)itemAtIndexPath:(NSIndexPath *)indexPath{
return _items[indexPath.row];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
FYBaseCell *cell = (FYBaseCell *)[tableView dequeueReusableCellWithIdentifier:_cellIdentifier];
if (_cellType == kFYCellTypeDefault) {
if (!cell) {
cell = [[DemoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_cellIdentifier];
}
}
id item = [self itemAtIndexPath:indexPath];
[cell configureCellContentWithItem:item];
return cell;
}
這些 dataSource 方法可以不用在 viewControllers 中實現(xiàn),因為 viewControllers 并不關(guān)心 cell 如何展示數(shù)據(jù),所以我們可以抽象出一個 FYDataSource 類出來,實現(xiàn) UITableViewDataSource 代理方法
@interface FYDataSource()
@property (nonatomic, copy) NSString *cellIdentifier;
@property (nonatomic, assign) kFYCellType cellType;
@end
- (id)itemAtIndexPath:(NSIndexPath *)indexPath{
return _items[indexPath.row];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
FYBaseCell *cell = (FYBaseCell *)[tableView dequeueReusableCellWithIdentifier:_cellIdentifier];
if (_cellType == kFYCellTypeDefault) {
if (!cell) {
cell = [[DemoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_cellIdentifier];
}
}
id item = [self itemAtIndexPath:indexPath];
[cell configureCellContentWithItem:item];
return cell;
}
我們再給這個抽象類添加一個實例方法,下面貼出 FYDataSource 這個類的頭文件代碼
// FYDataSource.h 文件的代碼
typedef NS_ENUM(NSInteger, kFYCellType){
kFYCellTypeDefault = 0,
};
@interface FYDataSource : NSObject <UITableViewDataSource>
@property (nonatomic, strong) NSArray *items; //模型數(shù)組
/**
* 創(chuàng)建一個FYDataSource對象
*
* @param items 模型數(shù)組
* @param cellIdentifier cell的緩存標(biāo)識符
* @param cellType cell類型
*
* @return 實例好的FYDataSource對象
*/
- (instancetype)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier cellType:(kFYCellType)cellType;
@end
*這樣就成功剝離了 UITableViewDataSource 的代理方法,并且多了 FYDataSource 這個工具類, ?可以復(fù)用, 與此同時你可以實現(xiàn)其它 UITableViewDataSource 代理方法,比如: *
tableView:commitEditingStyle:forRowAtIndexPath:
同樣的方法你也可以使用在 UICollectionViewDataSource 這個類上,趕緊給你的 viewControllers 瘦身吧!
*2. 剝?nèi)?UITableViewDelegate 方法 *
*同樣 UITableViewDelegate 的代理方法在控制器中也占據(jù)這不少的篇幅,我們也可以給它剝離出來,這里我把代理方法在 FYDataSource 中,同時通過代理傳出一些必要參數(shù)給控制器,代碼如下: *
// .h 文件
@protocol FYDataSourceDelegate <NSObject>
@optional
/**
* 點擊cell的代理方法,傳出對應(yīng)的item模型以及對應(yīng)的tablview
*
* @param item 對應(yīng)的item
* @param tableView 對應(yīng)的tablview
*/
- (void)didSelectedCellWithItem:(id)item tableView:(UITableView *)tableView;
- (CGFloat)heightForHeaderInSection:(NSInteger)section tableView:(UITableView *)tableView;
- (UIView *)viewForHeaderInSection:(NSInteger)section tableView:(UITableView *)tableView;
- (CGFloat)heightForFooterInSection:(NSInteger)section tableView:(UITableView *)tableView;
- (UIView *)viewForFooterInSection:(NSInteger)section tableView:(UITableView *)tableView;
- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView;
@end
// .m 文件中的實現(xiàn)
#pragma mark
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
id item = [self itemAtIndexPath:indexPath];
return [_baseCell configureCellHeightWithItem:item];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
id item = [self itemAtIndexPath:indexPath];
FYBaseCell *cell = (FYBaseCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
[cell didSelectedWithItem:item];
if (self.delegate && [self.delegate respondsToSelector:@selector(didSelectedCellWithItem:tableView:)]) {
[self.delegate didSelectedCellWithItem:item tableView:tableView];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
if (self.delegate && [self.delegate respondsToSelector:@selector(heightForHeaderInSection:tableView:)]) {
return [self.delegate heightForFooterInSection:section tableView:tableView];
}
return 1.0f;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
if (self.delegate && [self.delegate respondsToSelector:@selector(heightForFooterInSection:tableView:)]) {
return [self.delegate heightForFooterInSection:section tableView:tableView];
}
return 1.0f;
}
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
if (self.delegate && [self.delegate respondsToSelector:@selector(viewForHeaderInSection:tableView:)]) {
return [self.delegate viewForHeaderInSection:section tableView:tableView];
}
return nil;
}
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
if (self.delegate && [self.delegate respondsToSelector:@selector(viewForFooterInSection:tableView:)]) {
return [self.delegate viewForFooterInSection:section tableView:tableView];
}
return nil;
}
* 3. 將某些邏輯移動到 Model 中 *
下面有一個例子,在控制器中給 user 屬性賦值一個列表屬性:
- (void)loadPriorities {
NSDate* now = [NSDate date];
NSString* formatString = @"startDate <= %@ AND endDate >= %@";
NSPredicate* predicate = [NSPredicate predicateWithFormat:formatString, now, now];
NSSet* priorities = [self.user.priorities filteredSetUsingPredicate:predicate];
self.priorities = [priorities allObjects];
}
如果我們把這些邏輯交給 ?User 來處理,控制器就會變得清潔了:
- (void)loadPriorities {
self.priorities = [self.user currentPriorities];
}
邏輯我們通過給 User 創(chuàng)建擴(kuò)展 User+Extensions.m 來處理:
- (NSArray*)currentPriorities {
NSDate* now = [NSDate date];
NSString* formatString = @"startDate <= %@ AND endDate >= %@";
NSPredicate* predicate = [NSPredicate predicateWithFormat:formatString, now, now];
return [[self.priorities filteredSetUsingPredicate:predicate] allObjects];
}
擴(kuò)展閱讀
Lighter View Controller
Clean Table View Code
總結(jié)
給控制器瘦身的方法還有很多,在這里就不一一說了,擴(kuò)展閱讀 介紹了不少,項目中如果用到的話可以節(jié)省不少開發(fā)時間,另外希望各位多多分享,共同進(jìn)步.
demo 地址