前言前段时间一直在学习iOS的架构。为什么?公司的架构一直是MVC。当我们正式启动时,该项目已经有超过100,000行代码。各大VC的代码一般都在2000行以上。关键是,我们在当前版本中只做了三分之一的业务逻辑......所以让我们重构架构。正文MVVMMVVM:Model-View-ViewModelMVVM其实是MVC的一种进化,将业务逻辑从VC解耦到ViewModel,实现VC的“瘦身”。让我们用代码来解释吧!做一个简单的登录判断:创建LoginViewModel(逻辑处理)、LoginModel(只放数据)、LoginViewController。这里不使用LoginView的目的是让初学者更好的专注于与ViewModel的解耦。当然,如果你了解了这些,你可以直接看Wzxhaha/RandomerFramework,这是我在做的独立项目Randomer的基本架构(SubClasses+Protocol+MVVM+RAC)和它的登录注册模块。也感谢王龙帅的这篇文章,为我打开了新世界的大门。在LoginModel中添加方法//.h-(instancetype)initWithUserName:(NSString*)usernamepassword:(NSString*)password;@property(nonatomic,copy,readonly)NSString*username;@property(nonatomic,copy,readonly)NSString*password;//.m-(instancetype)initWithUserName:(NSString*)usernamepassword:(NSString*)password{if(self=[superinit]){_username=username;_password=password;}returnsself;}没什么好说的关于这个是的,就是给Model添加一个初始化方法。添加方法#import"PersonModel.h"到LoginViewModel-(instancetype)initWithPerson:(PersonModel*)person;@property(nonatomic,assign,readonly)BOOLcanLogin;-(instancetype)initWithPerson:(PersonModel*)person{if(self)=[superinit]){//这里绑定模型后做处理password{if(username.length&password.length){returnYES;}else{returnNO;}}增加Model绑定ViewModel的初始化方法,以及判断账号密码是否有效的方法。那么VC(或者View)就可以直接获取判断结果NSLog(@"%d",viewModel.canLogin);简单的功能没有错。当你处理复杂的逻辑判断时,MVVM将具有巨大的优势。顺便说一下ReactiveCocoa。我之所以如此推崇MVVM,是因为RAC和MVVM太般配了!ReactiveCocoaRAC具有函数式编程和响应式编程的特点。如果对编程思想不熟悉,可以看看我的WZXProgrammingIdeasRAC***的用处是可以监听各种事件。RAC调用这个信号流,然后通过块回调接受信号。里面用到了很多block,所以一定要用好@weakify(self)和@strongify(self)。为什么说RAC和MVVM太兼容了?MVVM将方法解耦到ViewModel,但仍然需要VC(V)调用,所以判断什么时候调用的逻辑还是会很复杂。而RAC解决了这个问题,它负责监听事件,然后调用ViewModel进行逻辑判断。例如:[[_registerBtnrac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(idx){@strongify(self)[self.viewModeltoRegisterWithType:Register];}];[[_loginBtnrac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(idx)lf{@strongify(seself.viewModelloginWithUserName:self.usernameTextField.textpassword:self.usernameTextField.textSuccess:^(idresponse){}失败:^{SHOW_ERROR(@"error",@"账号或密码错误")}error:^(NSError*error){SHOW_ERROR(@"error",@"Networkconnectionfailed")}];}];RAC监听登录注册按钮,代码简洁紧凑。Demo请看这个Wzxhaha/RandomerFrameworkhttps://github.com/Wzxhaha/RandomerFramework或者简单版的WZXRACDemohttps://github.com/Wzxhaha/WZXRACDemo链式网络请求框架为什么要封装WZXNetworking?这是一个非常可怕的容错框架。[[WZXNetworkManagermanager].setRequest(@"http://192.168.1.40:8001").RequestType(POST).HTTPHeader(nil).Parameters(nil).RequestSerialize(RequestSerializerHTTP).ResponseSerialize(ResponseSerializerJSON)startRequestWithSuccess:^(idresponse){NSLog(@"成功");}失败:^{NSLog(@"失败");}];这里除了.setRequest(url)和startRequestWithSuccess失败方法外,其他的都不需要。你可以这样做:[[WZXNetworkManagermanager].setRequest(@"http://192.168.1.40:8001")startRequestWithSuccess:^(idresponse){NSLog(@"success");}failure:^{NSLog(@"failure");}];当有许多参数可供选择或可能更改的参数时,链接显示出惊人的优势。因为改起来很方便,增加或者修改一个方法就可以了。例如:更改为集中式API包应该如下所示:-(void)GET:(NSString*)urlparameters:(id)Parameterssuccess:(SuccessBlock)successfailure:(FailureBlock)failure;当你想添加一个Version属性来做判断API版本的时候,你可以做什么呢?只能重写方法,给方法加一个Version参数,然后对所有使用的网络请求都改方法。如果我们切换到分布式API封装,我们将不考虑比较。apiGeGet.apiResponseSerializerType=ResponseHerializerTypeGetHTTP;:^(idresponseObject,NSError*error){NSLog(@"responseObjectis%@",responseObject);if(error){NSLog(@"Erroris%@",error.localizedDescription);}}];[apiGeGetstart];结构是否过于松散?切换到WZXNetworking,我们只需要再添加一个方法和一个成员变量,然后在原来的方法WZXNetworkManager(idsome)后面添加一个.method()-(WZXNetworkManager*(^)(idsome))method{return^{self.XXX=somereturnsself;}}[[WZXNetworkManagermanager].setRequest(@"http://192.168.1.40:8001").method(some)startRequestWithSuccess:^(idresponse){NSLog(@"success");}失败:^{NSLog(@"失败");}];把代码放在这里:WZXNetworkinghttps://github.com/Wzxhaha/WZXNetworking至于链是怎么实现的,看WZXProgrammingIdeashttps://github.com/Wzxhaha/WZXProgrammingIdeas
