VM来处理业务逻辑
每一个控制器对应一个VM模型
>>>登录界面
步骤
- 搭建界面(登录界面)
- 自定义VM模型,继承与NSObject,命名**ViewModel
- 懒加载
- 把整个界面的一些业务逻辑处理完
- 业务逻辑
- 绑定模型
- 登录事件
- 处理文本框业务逻辑
- 设置登录按钮是否可以点击
- 用RAC宏
- 监听登录按钮的点击
- rac_signalForControlEvents
- 处理事件
- 创建登录命令RACCommand
#import "GlobeHeader.h" @interface HMJLoginViewModel : NSObject /**< 账号*/ @property (nonatomic, strong)NSString *name; /**< 密码*/ @property (nonatomic, strong)NSString *password; /**< 登录按钮命令*/ @property (nonatomic, strong, readonly)RACCommand *loginCommand; /**< 处理登录按钮是否允许点击*/ @property (nonatomic, strong, readonly)RACSignal *loginEnableSignal; @end
#import "MBProgressHUD+XMG.h" @implementation HMJLoginViewModel - (instancetype)init { if (self = [super init]) { [self setUp]; } return self; } - (void)setUp { //监听账号的属性值改变,把他们聚合成一个信号 _loginEnableSignal = [RACSignal combineLatest:@[RACObserve(self, name), RACObserve(self, password)] reduce:^id(NSString *name, NSString *pwd){ return @(name.length && pwd.length); }]; //处理登录按钮点击命令 _loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { //block: 执行命令就会调用 //block作用: 事件处理 //发送登录请求 NSLog(@"发送登录请求"); return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //发送数据 [subscriber sendNext:@"请求登录的数据"]; [subscriber sendCompleted]; }); return nil; }]; }]; //处理登录请求返回的结果 [_loginCommand.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"%@", x); }]; //处理登录执行过程 [[_loginCommand.executing skip:1] subscribeNext:^(id x) { if ([x boolValue] == YES) { //正在执行 NSLog(@"正在执行"); //显示蒙板 [MBProgressHUD showMessage:@"正在拼命加载ing..."]; }else { //执行完成 //隐藏蒙板 [MBProgressHUD hideHUD]; NSLog(@"执行完成"); } }]; }
#import "HMJLoginViewModel.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UITextField *nameField; @property (weak, nonatomic) IBOutlet UITextField *pwdField; @property (weak, nonatomic) IBOutlet UIButton *loginBtn; /**< VM*/ @property (nonatomic, strong)HMJLoginViewModel *loginM; @end @implementation ViewController - (HMJLoginViewModel *)loginM { if (_loginM == nil) { _loginM = [[HMJLoginViewModel alloc] init]; } return _loginM; } // MVVM:先创建VM模型,把整个界面的一些业务逻辑处理完 // VM:视图模型,处理界面上所有业务逻辑 // 每一个控制器对应一个VM模型 // VM:最好不要包括视图V - (void)viewDidLoad { [super viewDidLoad]; //绑定VM模型 [self bindViewModel]; //处理事件 [self loginEvent]; } //绑定VM模型 - (void)bindViewModel { //给视图模型的账号和密码绑定信号 RAC(self.loginM, name) = _nameField.rac_textSignal; RAC(self.loginM, password) = _pwdField.rac_textSignal; } //处理事件 - (void)loginEvent { //处理文本框的业务逻辑 //设置按钮能否点击 RAC(_loginBtn, enabled) = self.loginM.loginEnableSignal; //监听登录按钮点击 [[_loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { //处理登录事件 [self.loginM.loginCommand execute:nil]; }]; }
>>>网络请求数据
用豆瓣网—>最下面的开发者—>开发文档
MVVM + AFN
步骤:
1.控制器提供一个视图模型(requesViewModel),处理界面的业务逻辑
2.VM提供一个命令,处理请求业务逻辑
3.在创建命令的block中,会把请求包装成一个信号,等请求成功的时候,就会把数据传递出去。
4.请求数据成功,应该把字典转换成模型,保存到视图模型中,控制器想用就直接从视图模型中获取。
5.假设控制器想展示内容到tableView,直接让视图模型成为tableView的数据源,把所有的业务逻辑交给视图模型去做,这样控制器的代码就非常少了。
>>>>>HMJBook.h<<<<<<<<< @interface HMJBook : NSObject /**< 名称*/ @property (nonatomic, strong)NSString *title; /**< 价格*/ @property (nonatomic, strong)NSString *price; + (instancetype)bookWithDict:(NSDictionary *)dict; @end >>>>>>HMJBook.m<<<<<<< + (instancetype)bookWithDict:(NSDictionary *)dict { HMJBook *book = [[HMJBook alloc] init]; book.title = dict[@"title"]; book.price = dict[@"price"]; return book; }
>>>>>>>HMJRequestViewModel.h<<<<<<<<< #import "HMJGlobalHeader.h" @interface HMJRequestViewModel : NSObject /**< 请求命令*/ @property (nonatomic, strong)RACCommand *requestCommand; @end
>>>>>>>HMJRequestViewModel.m<<<<<<<<< #import "HMJBook.h" @implementation HMJRequestViewModel - (instancetype)init { if (self = [super init]) { [self setUp]; } return self; } - (void)setUp { //请求命令 _requestCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { //发送信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { //创建请求管理者 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; //发送GET请求 [manager GET:@"https://api.douban.com/v2/book/search" parameters:@{@"q": @"美食"} success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) { //请求成功 NSLog(@"请求成功"); //写入plist // [responseObject writeToFile:@"/Users/XXX/Desktop/foods.plist" atomically:YES]; NSArray *dictArr = responseObject[@"books"]; NSArray *modelArr = [[dictArr.rac_sequence map:^id(id value) { return [HMJBook bookWithDict:value]; }] array]; [subscriber sendNext:modelArr]; } failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) { NSLog(@"请求失败"); }]; return nil; }]; return signal; }]; } @end
>>>>>ViewController.m<<<<<<<<<< #import "HMJGlobalHeader.h" #import "HMJRequestViewModel.h" @interface ViewController () /**< 请求模型*/ @property (nonatomic, strong)HMJRequestViewModel *requestVM; @end @implementation ViewController - (HMJRequestViewModel *)requestVM { if (_requestVM == nil) { _requestVM = [[HMJRequestViewModel alloc] init]; } return _requestVM; } - (void)viewDidLoad { [super viewDidLoad]; //发送请求 RACSignal *signal = [self.requestVM.requestCommand execute:nil]; [signal subscribeNext:^(id x) { }]; } @end