zoukankan      html  css  js  c++  java
  • MVVM

    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
  • 相关阅读:
    bzoj1505 [NOI2004]小H的小屋
    最大值
    数学
    OI中的快速傅里叶变换(FFT)
    旅游规划
    加分二叉树
    浅谈 字符串hash
    二分的弟弟“三分”
    Trie树(c++)
    克鲁斯卡尔
  • 原文地址:https://www.cnblogs.com/HMJ-29/p/4944014.html
Copyright © 2011-2022 走看看