1.理解:
MVVM是一種設計模式,本質在于ViewModel與View或Controller層進行綁定,model層數據變化可以通過ViewModel直接更新UI。
開發過程中,從可讀性和開發效率上簡單的視圖傾向于Controller持有特定的ViewModel。
2.優勢
(1)簡化開發
一個Controller針對某一任務持有其ViewModel,而非View或者subView持有,只需要維護Controller這一層的ViewModel;
(2)解耦
讓View專注于視圖和視圖邏輯,ViewModel專注于邏輯處理、網絡請求、數據解析以及暴露數據接口;
(3)便于測試,高復用性
View和ViewModel由于低耦合性,可以方便被其它模塊調用。ViewModel可以單獨調試。
3.使用場景
場景:博文列表
屬性 | 類型 |
---|---|
authorLabel作者 | UILabel |
avatarImgView頭像 | UIImageView |
contentLabel博文 | UILabel |
Cell層,提供外部訪問的組件
@interface BlogCell : TYBaseTableViewCell
/// 作者
@property (nonatomic, strong) UILabel *authorLabel;
/// 頭像
@property (nonatomic, strong) UIImageView *avatarImgView;
/// 博文
@property (nonatomic, strong) UILabel *contentLabel;
@end
ViewModel層,提供數據源,提供方式給C層Subscribe,從而刷新數據,以下提供3種方式狀態值,RACSubject,RACCommand
@interface BlogViewModel : NSObject
/// 數據源
@property (nonatomic, strong) NSMutableArray *dataArray;
/// 狀態:刷新狀態
@property (nonatomic, assign) TYStatus status;
/// 單向
@property (nonatomic, strong) RACSubject *subject;
/// 雙向
@property (nonatomic, strong) RACCommand *command;
@end
Controller層,視圖的配置和初始化等,主要有3塊:1、cell的賦值 2、UI邏輯下拉刷新 3、UI邏輯加載更多
// Cell的配置和賦值
[listView setConfigCellBlock:^UITableViewCell * _Nonnull(UITableView * _Nonnull table, NSIndexPath * _Nonnull indexPath) {
BlogCell *cell = [table dequeueReusableCellWithIdentifier:NSStringFromClass([BlogCell class])];
if (indexPath.row < weakSelf.blogVM.dataArray.count) {
id info = weakSelf.blogVM.dataArray[indexPath.row];
cell.avatarImgView.image = [UIImage imageNamed:info[@"avatar"]];
cell.authorLabel.text = info[@"author"];
cell.contentLabel.text = info[@"content"];
}
return cell;
}];
// 刷新
[listView setRefreshBlock:^{
[weakSelf request];
}];
// 加載更多
[listView setLoadMoreBlock:^{
[weakSelf loadMore];
}];
Controller層,綁定ViewModel和更新View,以下提供2種方式,RACSubject和自定義狀態
- (void)bind {
@weakify(self);
[self.blogVM.subject subscribeNext:^(id _Nullable x) {
// ....
}];
[RACObserve(self.blogVM, status)subscribeNext:^(id _Nullable x) {
@strongify(self);
NSInteger val = [x integerValue];
if (val == TYStatusRefreshCompleted) {
[self.listView endRefresh];
[self.listView reloadData];
}
else if (val == TYStatusLoadCompleted) {
[self.listView endLoadingMore];
[self.listView reloadData];
}
}];
}