MVVM 与RAC 网络请求

MVVM: Model-View-ViewModel


MVVM其实是MVC的进化版,它将业务逻辑从VC中解耦到ViewModel,来实现VC大’瘦身’。


用代码解释吧!


做一个简单的登录判断:


创建LoginViewModel(逻辑处理),LoginModel(只放数据),LoginViewController。

这里不用LoginView是为了让初学者能更好的把精力集中在用ViewModel解耦上。


当然要是你这些都明白,你可以直接看Wzxhaha/RandomerFramework,这是我在做的独立项目Randomer的基本架构(SubClasses+Protocol+MVVM+RAC)以及它的登录注册模块。另外,感谢王隆帅的这篇文章为我打开了新世界的大门。


在LoginModel中加入方法


//.h

(instancetype)initWithUserName:(NSString *)username password:(NSString *)password;

 

@property (nonatomic,copy,readonly)NSString * username;

@property (nonatomic,copy,readonly)NSString * password;


//.m

(instancetype)initWithUserName:(NSString *)username password:(NSString *)password {

    if (self = [super init]) {

        _username = username;

        _password = password;

    }

    return self;

}


这个没什么好讲的,就是给Model加一个初始化方法。


在LoginViewModel中加入方法


#import "PersonModel.h"

 

(instancetype)initWithPerson:(PersonModel *)person;

@property (nonatomic,assign,readonly)BOOL canLogin;


(instancetype)initWithPerson:(PersonModel *)person {

    if (self = [super init]) {

     //在这做你绑定model后的处理

      _canLogin = [self valiCanLoginWithUserName:person.username password:person.password];

    }

    return self;

}

 

(BOOL)valiCanLoginWithUserName:(NSString *)username password:(NSString *)password {

    if (username.length & password.length) {

        return YES;

    } else {

        return NO;

    }

}


给ViewModel添加个绑定Model的初始化方法,以及判断帐号密码是否有效的方法。


然后VC(或者View)就可以直接这样获得判断后的结果


PersonModel * person = [[PersonModel alloc]initWithUserName:@"10" password:@"10"];

PersonViewModel * viewModel = [[PersonViewModel alloc]initWithPerson:person];

 

NSLog(@"%d",viewModel.canLogin);


简单的功能的时候没什么,当你处理复杂的逻辑判断的时候,MVVM会有巨大优势。


顺便讲一下ReactiveCocoa,我之所以这么推崇MVVM,主要就是因为RAC和MVVM简直太配了!


ReactiveCocoa


RAC具有函数式编程和响应式编程的特性,要是对编程思想不熟的可以看我的WZXProgrammingIdeas


RAC最大的用处就是能监听到各个事件,RAC把这个叫做信号流,然后接受信号通过block回调,里面大量的使用了block,所以一定要用好@weakify(self)和@strongify(self)。


为什么说RAC和MVVM太配了?


MVVM是把方法解耦到ViewModel,但是还是要VC(V)调用的,那么判断什么时候调用的逻辑还是会复杂。


而RAC解决了这个问题,它负责监听事件,然后调用ViewModel来进行逻辑判断。


例如:


   [[_registerBtn rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(id x) {

        @strongify(self)

        [self.viewModel toRegisterWithType:Register];

    }];

 

    [[_loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(id x) {

        @strongify(self)

        [self.viewModel loginWithUserName:self.usernameTextField.text password:self.usernameTextField.text Success:^(idresponse) {

        } failure:^{

            SHOW_ERROR(@"错误", @"账号或密码错误")

        } error:^(NSError *error) {

            SHOW_ERROR(@"错误", @"网络连接失败")

        }];

    }];


RAC监听了登录和注册按钮,使得代码简洁,而且结构十分紧凑。


Demo的话还是看这个吧Wzxhaha/RandomerFramework

https://github.com/Wzxhaha/RandomerFramework


或者简单版的WZXRACDemo

https://github.com/Wzxhaha/WZXRACDemo


链式网络请求框架


为什么封装WZXNetworking


这是一个容错性非常吓人的框架。


[[WZXNetworkManagermanager].setRequest(@"http://192.168.1.40:8001").RequestType(POST).HTTPHeader(nil).Parameters(nil).RequestSerialize(RequestSerializerHTTP).ResponseSerialize(ResponseSerializerJSON) startRequestWithSuccess:^(id response) {

 

        NSLog(@"success");

    } failure:^{

 

        NSLog(@"failure");

    }];


在这里除了.setRequest(url)和startRequestWithSuccess failure方法,其他都是非必要的。


你可以这样:


[[WZXNetworkManager manager].setRequest(@"http://192.168.1.40:8001") startRequestWithSuccess:^(id response) {

 

        NSLog(@"success");

    } failure:^{

 

        NSLog(@"failure");

    }];


链式在参数和参数的选择很多的情况或者很有可能改动的情况下展现了惊人的优势。因为,它的改动十分方便,只不过添加或者修改一个方法。


打个比方:


换成集中式API封装应该是这样的:


(void)GET:(NSString *)url

        parameters:(id)Parameters

        success:(SuccessBlock)success

        failure:(FailureBlock)failure;


当你要添加一个Version属性做API版本判断的时候,你能怎么办?只能重写方法,在方法中加入一个Version参数,然后所有使用的网络请求都要改变方法。


换成分布式API封装我们则不考虑对比了..


GeneralAPI *apiGeGet            = [[GeneralAPI alloc] initWithRequestMethod:@"get"];

apiGeGet.apiRequestMethodType      = RequestMethodTypeGET;

apiGeGet.apiRequestSerializerType  = RequestSerializerTypeHTTP;

apiGeGet.apiResponseSerializerType = ResponseSerializerTypeHTTP;

[apiGeGet setApiCompletionHandler:^(id responseObject, NSError * error) {

    NSLog(@"responseObject is %@", responseObject);

    if (error) {

        NSLog(@"Error is %@", error.localizedDescription);

    }

}];

[apiGeGet start];


这样的结构是否太松散?


再换成WZXNetworking


我们要做的只是再添加一个方法和一个成员变量,然后在原有方法后面加一个.method()


(WZXNetworkManager * (^) (id some))method {

  return ^WZXNetworkManager (id some) {

     self.XXX = some

     return self;

  }

}


[[WZXNetworkManager manager].setRequest(@"http://192.168.1.40:8001").method(some) startRequestWithSuccess:^(idresponse) {

 

        NSLog(@"success");

    } failure:^{

 

        NSLog(@"failure");

    }];


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值