zoukankan      html  css  js  c++  java
  • 谈谈MVVM和链式网络请求架构

    前言

    前一段时间一直在学习iOS的架构。为什么呢?

    公司的架构一直是MVC,当我们正式上线的时候,项目已经有了超十万行代码。主要的VC一般都有2000行代码以上。

    关键是,目前版本我们只做了三分之一的业务逻辑…

    所以,架构重构吧。

    正文

    MVVM

    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:^(id response) {

            } failure:^{

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

            } error:^(NSError *error) {

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

            }];

        }];

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

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

    https://github.com/Wzxhaha/RandomerFramework

    或者简单版的WZXRACDemo

    https://github.com/Wzxhaha/WZXRACDemo

    链式网络请求框架

    为什么封装WZXNetworking

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

    [[WZXNetworkManager manager].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:^(id response) {

            NSLog(@"success");

        } failure:^{

            NSLog(@"failure");

        }];

    代码放这:WZXNetworking

    https://github.com/Wzxhaha/WZXNetworking

    至于链式是怎么实现的,还是看那个WZXProgrammingIdeas

    https://github.com/Wzxhaha/WZXProgrammingIdeas

  • 相关阅读:
    智慧光伏能源-园区光伏发电能源管控可视化
    无人值守,智能变电站可视化管控系统
    数字孪生,开启三维智慧园区管理新篇章
    智慧城市大数据运营中心 IOC 之 Web GIS 地图应用
    三维可视化数据中心机房监控管理系统
    打造绿色城市,数字孪生天然气站 3D 可视化
    绿色物流-智慧仓储监控管理 3D 可视化系统
    打造综合性智慧城市之朔州开发区 3D 可视化
    绿色城市之地下综合管廊3D可视化平台
    工业绿色环保发展:风力发电场管理监测可视化系统
  • 原文地址:https://www.cnblogs.com/fengmin/p/5453796.html
Copyright © 2011-2022 走看看