MVVM的理解
Model层是数据模型层。
ViewModel层,就是View和Model层的粘合剂,他用来放置用户输入验证逻辑,视图显示逻辑,以及发起网络请求等等。是把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。
View层,就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。
使用MVVM模式,实现VM和View层的通信,可以使用KVO,Block,Delegate,Notification,或者ReactiveCocoa。ReactiveCocoa就是一个响应式编程的框架,它会使MVVM每层之间交互起来更为方便,所以经常和MVVM联系在一起。
为了使得项目结构更加的合理,通常会将VM中共通的部分提取出来,定义在一个基类中,而具体的实现细节则交由各个子类各自定义。
如定义基类(使用Block的形式来实现VM和View之间的通信):
typedef void(^BaseVoidBlock)();
@protocol BaseViewModelActionProtocol <NSObject>
@optional
/**
刷新数据(这里是将网络通信部分提取出来)
@param preprocess HUD处理block
@param finished 刷新完成block
@param failed 异常block
*/
- (void)actionToDealReloadDataSourcePreprocess:(BaseVoidBlock)preprocess
onFinished:(BaseVoidBlock)finished
onFailed:(BaseVoidBlock)failed;
@end
@interface BaseViewModel :NSObject<BaseViewModelActionProtocol>
@property (nonatomic, strong) NSMutableArray *dataSource;
@property (nonatomic, strong) NSString *failedMsg; // 访问异常原因
@property (nonatomic, copy) BaseVoidBlock blockReload; // 重新刷新数据 block
@end
子类定义:
#import "BaseViewModel.h"
typedef NS_ENUM(NSInteger, ChildVMRowType) {
ChildVMRowTypeName = 0, // 姓名
ChildVMRowTypePass, // 密码
};
@interface ChildVM : BaseViewModel
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *password;
/**
获取输入框左侧图片名称
@param type 数据行类型 ChildVMRowType
@return 图片名称
*/
- (NSString *)cellLeftImageName:(ChildVMRowType)type;
/**
获取输入框的提示文字
@param type 数据行类型
@return 提示文字
*/
- (NSString *)cellPlaceholder:(ChildVMRowType)type;
/**
获取输入框内容
@param type 数据行类型
@return 输入框内容
*/
- (NSString *)cellText:(ChildVMRowType)type;
/**
判定信息是否合法
@return 无效描述。 nil标识数据有效
*/
- (NSString *)judageInvalidName;
@interface ChildVM()
@property (nonatomic, strong) ResultModel *model;
@end
@implementation ChildVM
- (NSString *)failedMsg {
return self.model.MESSAGE;
}
//网络通信的具体实现
- (void)actionToDealReloadDataSourcePreprocess:(BaseVoidBlock)preprocess onFinished:(BaseVoidBlock)finished onFailed:(BaseVoidBlock)failed {
RequestModel *reqModel = [[RequestModel alloc] init];
reqModel.name = self.name;
reqModel.password = self.password;
__weak typeof(self) weakSelf = self;
[self.model postRequestModel:reqModel preprocess:preprocess onFinished:^(NSError * _Nullable error, id _Nullable data) {
if (error) {
weakSelf.model.MESSAGE = @"网络开小差了,请稍后重试!";
if (failed) failed();
} else {
[weakSelf actionToDealDataSource:data];
if (finished) finished();
}
}];
}
- (NSString *)cellLeftImageName:(ChildVMRowType)type {
if (type == ChildVMRowTypeName) {
return @"name";
} else if (type == ChildVMRowTypePass) {
return @"password";
}
return @"";
}
- (NSString *)cellPlaceholder:(ChildVMRowType)type {
if (type == ChildVMRowTypeName) {
return @"请输入姓名";
} else if (type == ChildVMRowTypePass) {
return @"请输入密码";
}
return @"";
}
View层部分的相关通信部分:
- (void)actionToDoNext:(id)sender {
//调用VM中的逻辑判断部分
NSString *errMsg = [self.viewModel judageInvalidName];
if (errMsg.length > 0) {
[CustomIOSAlertView showTitle:@"提示" withText:errMsg andDone:@"确认"];
return;
}
//调用VM中的网络通信部分
__weak typeof(self) weakSelf = self;
[self.viewModel actionToDealReloadDataSourcePreprocess:^{
[SVProgressHUD show];
} onFinished:^{
[SVProgressHUD dismiss];
//成功后的处理
} onFailed:^{
[SVProgressHUD dismiss];
[CustomIOSAlertView showTitle:@"提示" withText:[weakSelf.viewModel failedMsg] andDone:@"确认"];
}];
}
如上所示,通过把ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层,极大的减轻了ViewController的负担,使得代码更加的间接明了。