MVVM模式下如何使用ReactiveCocoa响应链式编程<一>

  前一阵子公司要求项目从新架构,但又只给不到一个月的时间,这显然是不可能的。但从新架构又是在所难免的,和同事商定后决定一部分交互逻辑比较少的界面先使用MVVM架构,然后慢慢修改。下面整理了一下这次重构的遇到的问题,并希望能给大家一些帮助。

1.ReactiveCocoa的使用

要使用MVVM模式编程收下选择一个框架,当然不仅仅是ReactiveCocoa这一个框架,这里就不多说。当然我也没用过别的,如果哪位看官用过可以多多指教。接下来我就按步骤说了:

第一步:导入ReactiveCocoa框架,建议使用Cocopods管理这个第三方SDK,因为他帮我们解决了不少麻烦。首先你不用自己封装静态库,其次你也不用担心库路径会找不到,最后由于这个sdk目前使用的人并不多,所以以后随着使用者越来越多肯定会有更新。

关于sdk的下载可以参考截图,不多做介绍。其中MJExtension这个sdk也顺便导一下,因为MVVM少不了字典转模型的。当然不用也可以!

第二部:先从一个简单的界面开始,这是第一个MVVM模式下运用Ractivecocoa编写的第一个界面,不过基本涵盖了RAC(一下Ractivecocoa简称RAC)复杂Model下的数据请求和传递,先看一下界面实现的效果。点击第一个界面的历史红包,跳转到发红包界面:

我先把总体的方法给粘贴出来,首先有一个总体的思路把控,首先实现的的是历史红包点击cell的代理方法:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"TableView" bundle:nil];
    //1.MVVM下的MVVMCheakLuckViewController
    self.checkRedBag= (MVVMCheakLuckViewController *)[storyBoard instantiateViewControllerWithIdentifier:@"MVVMCheakLuckViewController"];
    NSDictionary *detailDic =self.dataArr[indexPath.row];
    NSString *bonus_codeStr = [NSString stringWithFormat:@"%@",[detailDic objectForKey:@"bonus_code"]];
    //2.抽象出一个“下载类”(可以把url或者需要上传的数据抽象成NetWorkingModel的属性)
    NetWorkingModel * networkModel = [[NetWorkingModel alloc] init];
    networkModel .bonusCode = bonus_codeStr;
    networkModel.urlPath = CheakLuck_URL;
    //3.初始化MVVMCheackLuckViewModel,这个就是MVVM中的ViewModel。正是把以前ViewController里面的数据下载剥离了出来,为ViewController瘦身。初始方法把“下载类”作为参数传入。
    MVVMCheackLuckViewModel * listVM = [[MVVMCheackLuckViewModel alloc] initWithAFRequestParameter: networkModel];
    //4.通过上面的2和3两步,最终的目的是对MVVMCheakLuckViewController的viewModel赋值
    self.checkRedBag.viewModel = listVM;
    //5.万事具备,跳转界面。
    [self.navigationController pushViewController:self.checkRedBag animated:YES];
}
我把关键解释加黑处理,帮助理解。可能看官对MVVM有了一个初步的了解,为了加深看官的理解彻底改变你MVC的编程思维,我把代码与MVC下的界面跳转作对比,实现效果是一样的还是上面的两个界面。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"TableView" bundle:nil];
    CheakLuckViewController * checkRedBag= (CheakLuckViewController *)[storyBoard instantiateViewControllerWithIdentifier:@"CheakLuckViewController"];
    
    NSDictionary *detailDic =self.dataArr[indexPath.row];
    NSString *bonus_codeStr = [NSString stringWithFormat:@"%@",[detailDic objectForKey:@"bonus_code"]];
    
    checkRedBag.bonusCode = bonus_codeStr;
    
    [self.navigationController pushViewController:checkRedBag animated:YES];
}
MVC我就不多做介绍了,相信每个人都很熟悉,看似简单整洁,但正是因为这里的简单整洁,反而加重了ViewController的负担。对比着其实我把沉重的ViewController里面的代码。剥离到2,3和4这三个步骤中去了,我在这仔细论述这三部的实现。

第2步,这一步很简单,但必须要培养一个建立Model的观念,这个类的代码也很简单:

#import <Foundation/Foundation.h>

@interface NetWorkingModel : NSObject
/**
 下载需要的上传的参数或者要拼接的参数
 */
@property (strong,nonatomic) NSString *bonusCode;

@property (strong,nonatomic) NSString *urlPath;

@end

第3步,这一步是最关键的一步,我们通过上面的下载类在MVVMCheackLuckViewModel中下载数据。这里简单用到了一些RAC的语法,我会做简单的介绍,首先RAC是一个响应式链式编程,我可以理解RAC像一个管道,通过一个个信号连接而成的一个管道。我们先看MVVMCheackLuckViewModel中的代码:

.h中的代码如下:
//传的参数
@property (copy,nonatomic)NSString *bonusCode;
@property (copy,nonatomic)NSString *requestPath;

//这个Model中是在关键的Model,存储了下载的数据。而且我们可以在MVVMCheakLuckViewController中通过ViewModel.cashModel的方法的到下载的数据,所以所有剥离出来的过程都是在给cashModel赋值。
@property (strong,nonatomic) CashRedBagModel *cashModel;

//对传过来的数据做一下储存
@property (strong,nonatomic) NetWorkingModel *saveNetModel;
类的初始化方法,通过这个方法是”下载类“,和ViewModel建立了连接,这才是下载数据成为可能
- (instancetype)initWithAFRequestParameter:(NetWorkingModel *)NetModel;
@end
.m中的方法

- (instancetype)initWithAFRequestParameter:(NetWorkingModel *)NetModel{
    self = [super init];
    self.saveNetModel = NetModel;
    //注册一个信号,它更像一个观察者,始终观察requestPath的值,一旦发生变化才会return Yes.才会执行subscribeNext下面的方法。所以如果以后你要改变requestPath换个Url从新请求数据,也不需要从新写下载的方法了。RAC内部也是通过KeyPath监听的。
    [[RACObserve(self, requestPath) filter:^BOOL(id value) {
        return value;
    }] subscribeNext:^(NSString * path) {
        //NSURLSessionConfiguration是苹果推荐的下载类,所以这里使用了NSURLSessionConfiguration下载数据(AF3.0),如果觉得不习惯可以使用NSURLconnection。AF3.0.4是两种都支持的
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
        //自己封装的方法创建AFrequest并在这个方法中完成数据上传
        NSMutableURLRequest *request = [self creatAFmangerURLRequest:path];
        NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
            if (error) {
                DLog(@"========Error: %@", error);
            } else {
                DLog(@"responseObject----------%@",responseObject);
                NSDictionary *responsedic = [responseObject objectForKey:@"d"];
                //通过cashModel初始化Taskuseramodel
                //字典转模型使用的是MJExtension
                CashRedBagModel *cashModel = [CashRedBagModel mj_objectWithKeyValues:responseObject];

      //1.对cashModel进行初始化,cashModel里还包含一个数组,数组里面存放的是TakeUserModel,对于这种复杂的Model,会在它的初始化方法里完整的对cashModel一一赋值,进而对TakeUserModel也进行初始化。由于这一步比较复杂我先标记一下。……&……&……&……
                [cashModel initCashsWithDictionary:responsedic];
                //2.第一步还要关联另外一个Model我们暂称为小Model,我们等会仔细说这个初始化方法。下面这句代码对controllers的Model赋值,经过第一步,这一步是最关键的一步。完成赋值之后就等于完成了数据下载,就只剩下MVVMCheakLuckViewController中ui的搭建和数据的展示了。
                self.cashModel = cashModel;
            }
        }];
        [dataTask resume];
    }];
    if (nil != self) {

//我们在上面注册了信号,但是第一次并不执行subscribeNext里的方法。因为self.requestPath = netModel.urlPath这一句之后filter的方法里才会return Yes。
        [RACObserve(self, saveNetModel)  subscribeNext:^(NetWorkingModel * netModel) {
            self.bonusCode = netModel.bonusCode;
            self.requestPath = netModel.urlPath;
         }];
    }
    return self;
}
未完待续

时间: 2024-10-25 13:46:17

MVVM模式下如何使用ReactiveCocoa响应链式编程<一>的相关文章

浅析WPF中MVVM模式下命令与委托的关系

??各位朋友大家好,我是Payne,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com.最近因为项目上的原因开始接触WPF,或许这样一个在现在来讲显得过时的东西,我猜大家不会有兴趣去了解,可是你不会明白对某些保守的项目来讲,安全性比先进性更为重要,所以当你发现银行这类机构还在使用各种"复古"的软件系统的时候,你应该相信这类东西的确有它们存在的意义.与此同时,你会更加深刻地明白一个道理:技术是否先进性和其流行程度本身并无直接联系.由此我们可以推论出:一项不流行

MVVM模式下的OpenFileDialog

对于MVVM模式下的ViewModel层来说,是不应该直接访问OpenFileDialog或者FolderBrowserDialog的,否则VM会变得难以测试. 参考StackOverFlow,对ViewModel进行改造,使OpenFileDialog动作也可以测试. 首先实现接口IIOService public interface IIOService { string OpenFileDialog(string srcFilter = ""); IList<string&

js架构设计模式——MVVM模式下,ViewModel和View,Model有什么区别

MVVM模式下,ViewModel和View,Model有什么区别 Model:很简单,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model. View:也很简单,就是展现出来的用户界面. 基本上,绝大多数软件所做的工作无非就是从数据存储中读出数据,展现到用户界面上,然后从用户界面接收输入,写入到数据存储里面去.所以,对于数据 存储(model)和界面(view)这两层,大家基本没什么异议.但是,如何把model展现到view上,以及如何把数据从view写入到m

MVVM模式下 DataTemplate 中控件的绑定

原文:MVVM模式下 DataTemplate 中控件的绑定 今天给ListBox中通过DataTemplate生成的Button绑定命令时,一开始Button始终找不到绑定的命令.现找到了正确的绑定方式,特来记录一下. 先上个正确的示例: <ListBox Grid.Column="0" ItemsSource="{Binding CallBussiness}"> <ListBox.ItemsPanel> <ItemsPanelTem

WPF MVVM模式下动画的实现

原文:WPF MVVM模式下动画的实现 在MVVM模式下,数据的显示都是通过绑定来实现的.当我们在ViewModel里修改数据时,View里面的界面会瞬间变化.但是如果我们希望这个变化有一个动画效果,应该怎么做呢? 可能一开始我们会想到DoubleAnimation.StoryBoard这些东西,但我们很快就会发现,它们只能操作View里面的元素,我们无法在ViewModel里使用它们. 我们在这里使用的方法是:创建一个类似DoubleAnimation的类,它的操作对象就是普通的double类

ReactiveCocoa链式编程初探

在使用 masonry 框架实现自动布局时,在程序里为一个布局穿插着6行左右这样的代码 [View mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(anotherView); make.left.equalTo(anotherView); make.width.mas_equalTo(@60); make.height.mas_equalTo(@60); }]; 一直觉得不够漂亮,希望有个一行代码设置约束的框架

链式编程思想

接下来的部分摘自:最快让你上手之ReactiveCocoa基础篇 先简单介绍下目前咱们已知的编程思想. 1 面向过程:处理事情以过程为核心,一步一步的实现. 2 面向对象:万物皆对象 3 链式编程思想:是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好.a(1).b(2).c(3) 链式编程特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值) 代表:Masonry框架. 4 响应式编程思想:不需要考虑调用顺序,只需要知道考虑

iOS开发技巧系列---使用链式编程和Block来实现UIAlertView

UIAlertView是iOS开发过程中最常用的控件之一,是提醒用户做出选择最主要的工具.在iOS8及后来的系统中,苹果更推荐使用UIAlertController来代替UIAlertView.所以本文也并不提倡开发者再使用UIAlertView,本文的目的是探讨如何将原来的给变量赋值和通过Delete来回调的方式变成链式编程风格和通过Block来回调.通过学习对UIAlertView的改造让各位iOS开发者能够学会这种更加便捷的开发方式 什么是链式编程 对于有一定开发经验的开发者来说,链式编程

数往知来 JQuery_选择器_隐式迭代_链式编程 &lt;二十&gt;

一.通过js实现页面加载完毕执行代码的方式与jquery的区别 1.通过jquery的方式可以 让多个方法被执行,而通过window.onload的方式只能执行最后一个, 因为最后一次注册的方法会把前面的方法覆盖掉 1. window.onload需要等待页面的所有元素资源比如说img里的图片一些连接等等都下载完毕后才会触发: 2. 而jquery只要页面的标签元素都下载完毕就会触发了 二.$.map(数组,function(ele,index){})函数对数组进行遍历,遍历之后会返回一个新的数