一、關於MVVM設計模式
網上的介紹很多,簡單說下我的理解。
個人理解:
MVVM = 控制器 + 視圖 + 數據模型 + 視圖模型
其中 視圖模型View - Model 是將 控制控制器中的 網絡請求 下拉刷新 下拉加載 及用戶交互操作 剝離出來 放到一個工具類裡面 由此達到解耦合為控制器瘦身的目的。
二、關於小型工廠模式的使用
開發過程中UITableView的使用頻率很高,可你是怎樣創建tableView的呢?UITableViewController是一個不錯的選擇,自帶一個tableView 而且你需要做的只是實現它的協議方法就可以了。省去了創建tableView 簽代理的麻煩,而且UITableViewController繼承於UIViewController 所以跟你在UIViewController上創建tableView沒區別。
此時問題來了,當你的tableView的cell有多種的時候怎麼辦?肯定是在返回cell的協議方法裡面進行判斷了。可是這樣你不會覺得看著很亂麼?而且返回行高的時候也需要判斷,這就不可避免增加控制器的代碼量,而且返回cell的類型明顯不是控制器的責任,控制器只是起協調作用的。這時我們就想可不可以把cell的返回類型 返回行高抽出一個類來實現呢?通過傳入一些參數 直接返回對應的行高 cell類型。答案是肯定的。
上面所說ViewModel則可以實現網絡請求 用戶交互 等業務邏輯 只需傳入對應的參數就好。
效果如下:
// Demo用到的API為新浪新聞 ,一共三種cell。
三、具體實現
實踐出真知,通過一個簡單的例子感受下。
新建類:
1.網絡請求類:JWNetTool,簡單對AFN做一個封裝
2.數據模型:JWModel
創建一些用得到的屬性,封裝初始化方法,重寫 -(void)setValue:(id)value forUndefinedKey:(NSString *)key
3.ViewModel
4.cell工廠
內部實現
#import "JWCellFactory.h"
#import "JWModel.h"
@implementation JWCellFactory
+ (UITableViewCell *)creatTableViewCellWithModel:(JWModel *)model TableView:(UITableView *)tableView IndexPath:(NSIndexPath *)indexPath
{
return [self creatTableViewCellWithModel:model TableView:tableView IndexPath:indexPath CellType:[self cellTypeWithModel:model]];
}
+ (UITableViewCell *)creatTableViewCellWithModel:(JWModel *)model TableView:(UITableView *)tableView IndexPath:(NSIndexPath *)indexPath CellType:(CellType)type
{
UITableViewCell *cell = nil;
switch (type) {
case 1:
cell = [tableView dequeueReusableCellWithIdentifier:@"JWOnePictureCell"];
tableView.rowHeight = 120;
break;
case 0:
cell = [tableView dequeueReusableCellWithIdentifier:@"JWBigPictureCell"];
cell.backgroundColor = [UIColor yellowColor];
tableView.rowHeight = 150;
break;
case 2:
cell = [tableView dequeueReusableCellWithIdentifier:@"JWThreePicsCell"];
cell.backgroundColor = [UIColor greenColor];
tableView.rowHeight = 180;
break;
default:
break;
}
return cell;
}
+(CellType)cellTypeWithModel:(JWModel *)model
{
if (![model.category isEqualToString:@"hdpic"]) {
if ([model.category isEqualToString:@"cms"]) {
return NewsOneImageCell;
}else{
return NewsOneBigImageCell;
}
}
return NewsThreeImageCell;
}
@end
5.接下來我們看下控制器裡的代碼:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.models.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
return [JWCellFactory creatTableViewCellWithModel:self.models[indexPath.row] TableView:tableView IndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[JWViewModel cellSeletedActionWithTableView:tableView IndexPath:indexPath ViewController:self Arr:self.models];
}
再看下數據請求相關代碼:
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
[JWViewModel getDataWithUrl:URL TableView:self.tableView ViewController:self];
}];
[self.tableView.mj_header beginRefreshing];
#pragma mark - 下拉加載的實現
self.tableView.mj_footer = [MJRefreshAutoStateFooter footerWithRefreshingBlock:^{
[JWViewModel getMoreDataWithUrl:MORE TableView:self.tableView ViewController:self Models:self.models];
}];
6.看下注冊cell方法
[self.tableView registerNib:[UINib nibWithNibName:@"JWOnePictureCell" bundle:nil] forCellReuseIdentifier:@"JWOnePictureCell"];
[self.tableView registerNib:[UINib nibWithNibName:@"JWBigPictureCell" bundle:nil] forCellReuseIdentifier:@"JWBigPictureCell"];
[self.tableView registerNib:[UINib nibWithNibName:@"JWThreePicsCell" bundle:nil] forCellReuseIdentifier:@"JWThreePicsCell"];
看到這裡瘦身該做的已經差不多了接下來談談tableView一些可以優化的地方
四、UITableView相關優化
1.行高固定用屬性賦值:
能不用協議方法就不用協議方法,如果行高確定則通過self.tableView.rowHeight = 100;來賦值
因為協議方法的話會在初始化的時候走很多次 , 假設當前數組有20條數據
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 這個方法會走60次 而且每當一個cell出現的時候都會再走一次這個方法。多次走這個方法主要是動態獲取當前tableView的contentSize這一屬性。
所以行高確定的話 屬性賦值會節省一定的資源
2.行高非固定的話 -> 可以采用緩存機制 將已有行高緩存到字典 下次用的時候可以直接取出 不必再重新計算
3.行高動態變化 但變化幅度不是很大 那麼就可以采用估算的方法了.假如行高在120 左右變化 且幅度不是很大 的話 self.tableView.estimatedRowHeight = 120;- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
再結合協議方法緩存行高達到優化作用。
4.刷新方法
insertRowsAtIndexPaths:<#(nonnull NSArray*)#> withRowAnimation:<#(UITableViewRowAnimation)#>
與 reloaData
試想一下 如果我現在已經有1000行cell了,而且都是行高都是動態的那麼我再獲取20行cell 之後reloaData 那麼可以想象了 從第0行一直刷新到第1019行 ,這是很浪費資源的.所以可以采用insert方法去更新cell
Demo中ViewModel上拉加載方法裡有用到:
for (NSDictionary *temp in list) {
JWNewsModel *model = [JWNewsModel modelWithDic:temp];
[arr addObject:model];
vc.dataArr = arr;
[tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:arr.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
5.異步繪制cell 有興趣的可以去查一下
6.cell盡量手動創建 盡量少用Xib畢竟 加載時轉化成代碼也會消耗一定的時間
7.cell盡量不那麼復雜 圖層盡量少 畢竟cell復雜 繪制的話會消耗更多的時間
8.按需加載cell如果我現在飛快的滑動tableView的話 是不是中間有幾個cell沒必要立馬創建出來 而是首先創建屏幕將要顯示的cell?