论RAC+MVVM 模式下的网络请求

摘要:首先我简单的说一下,RAC、MVVM 是啥。RAC:即ReactiveCocoa 是一套函数式编程的框架,确实很好使用,可以节省很多开发时间。当下Swift也提供很多相似的高阶函数,学习一下还是很有必要的,我这里给几个链接有兴趣的可以看一下。https://www.jianshu.com/p/87e

首先我简单的说一下,RAC、MVVM 是啥。

RAC:即ReactiveCocoa 是一套函数式编程的框架,确实很好使用,可以节省很多开发时间。当下Swift也提供很多相似的高阶函数,学习一下还是很有必要的,我这里给几个链接有兴趣的可以看一下。
https://www.songma.com/p/87ef6720a096
https://www.songma.com/p/e10e5ca413b7

MVVM:由MVC演变而来的,为Controller 减负的设计模式。

RAC在MVVM设计中,充任胶水的角色。

1、数据绑定:作使用View和ViewModel之间,但ViewModel中数据由于使用户的操作变化时,View更改马上升级。
2、网络请求: 把网络请求封装成Command,在View层触发网络访问
3、Model 数据变化的时候,升级ViewModel数据

逻辑关系请看下图:


rac.png

这里只是简单的形容了一下RAC+MVVM,下面重点详情一下其中网络请求的部分。在实际开发过程中,网络请求部分与以前的block后调方式有细微的差别。我这里使用信号的方式返回数据,View层,通过Command 命令订阅返回数据,这里封装成了一个工具:FMARCNetwork( zhufaming/ZFMRACNetwork)

简单的思维导图:


shiwei.png

工具用的主要三方框架:

source ' CocoaPods/Specs.git'platform :ios, '8.0'target 'ZFMRACNetwork' do       #AFN -->不解释    pod 'AFNetworking'     #ReactiveCoca  --> ReactiveCocoa 对OC的支持    pod 'ReactiveObjC', '~> 3.1.0'       #网络提醒--> 网络监听显示,主要是展现状态    pod 'JDStatusBarNotification', '~> 1.5.6'       #提醒 -->主要的提醒库    pod 'MBProgressHUD', '~> 1.1.0'  end

项目结构:


jiegou.png

ZFMRACNetworkTool.h : 工具引使用.h文件,用工具,#import 一下即可以了
FMHttpConstant.h 网络请求相关的宏定义
FMHttpRequest.h 请求相关的参数配置
FMHttpResonse.h 网络请求响应的,信号返回的数据模型
FMARCNetwork 网络请求主要的工具类

单例设计工具类:

@interface FMARCNetwork : NSObject+(instancetype) sharedInstance;/** 网络请求,返回信号 按照, FMHttpRequest 参数化设置 @param req FMHttpRequest @return RACSignal */- (RACSignal *)requestNetworkData:(FMHttpRequest *)req;/** 网络请你,简便方案 @param path 请求路径 --- 基本链接,请在 FMHttpRConstant.h 文件中设置 @param params 参数字典 @return RACSignal */- (RACSignal *)requestSimpleNetworkPath:(NSString *)path params:(NSDictionary *)params;/** 文件上传、可以当个文件、也可以多个文件 @param path 文件上传服务器地址,这里单独给出来,是由于很大部分图片服务器和业务服务器不是同一个 @param params 参数 没有可传 @{} @param fileDatas NSData 数组 @param name 指定数据关联的名称 @return RACSignal */- (RACSignal *)uploadNetworkPath:(NSString *)path params:(NSDictionary *)params fileDatas:(NSArray<NSData *> *)fileDatas name:(NSString *)name mimeType:(NSString *)mimeType;@end

方法简介:
requestNetworkData : 通使用请求,可以通过FMHttpRequest 配置请求的方式:Get or Post

requestSimpleNetworkPath: 简单的网络请求,传url 当然是字符串了,字典参数,默认Post 请求。这样设计的目的其实现在很少有使用get 的请求了。

uploadNetworkPath: 文件或者图片的上传。

实现:

- (RACSignal *)requestNetworkData:(FMHttpRequest *)req{     /// request 必需的有值    if (!req) return [RACSignal error:[NSError errorWithDomain:HTTPServiceErrorDomain code:-1 userInfo:nil]];        @weakify(self);    /// 创立信号    RACSignal *signal = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {        @strongify(self);        /// 获取request                //假如需要 额外的参数,请追加到参数字典里面去        //ExtendsParameters *exParams = req.extendsParameters;                NSError *serializationError = nil;        NSMutableURLRequest *request = [self.manager.requestSerializer requestWithMethod:req.method URLString:[[NSURL URLWithString:req.path relativeToURL:[NSURL URLWithString:BaseUrl] ] absoluteString] parameters:req.parameters error:&serializationError];                if (serializationError) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wgnu"            dispatch_async(self.manager.completionQueue ?: dispatch_get_main_queue(), ^{                [subscriber sendError:serializationError];            });#pragma clang diagnostic pop            return [RACDisposable disposableWithBlock:^{            }];        }        /// 获取请求任务        __block NSURLSessionDataTask *task = nil;        task = [self.manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {             @strongify(self);            if (error) {                NSError *parseError = [self errorFromRequestWithTask:task httpResponse:(NSHTTPURLResponse *)response responseObject:responseObject error:error];                    NSInteger code = [parseError.userInfo[HTTPServiceErrorHTTPStatusCodeKey] integerValue];                NSString *msgStr = parseError.userInfo[HTTPServiceErrorDescriptionKey];                //初始化、返回数据模型                FMHttpResonse *response = [[FMHttpResonse alloc] initWithResponseError:parseError code:code msg:msgStr];                //同样也返回到,调使用的地址,也可解决,自己选择                [subscriber sendNext:response];                //[subscriber sendError:parseError];                [subscriber sendCompleted];                //错误可以在此处解决---比方加入自己弹窗,主要是服务器错误、和请求超时、网络开小差                [self showMsgtext:msgStr];                            } else {                              /// 判断                NSInteger statusCode = [responseObject[HTTPServiceResponseCodeKey] integerValue];                if (statusCode == HTTPResponseCodeSuccess) {                    FMHttpResonse *response = [[FMHttpResonse alloc] initWithResponseSuccess:responseObject[HTTPServiceResponseDataKey] code:statusCode];                                       [subscriber sendNext:response];                    [subscriber sendCompleted];                                    }else{                    if (statusCode == HTTPResponseCodeNotLogin) {                        //可以在此解决需要登录的逻辑、比方说弹出登录框,但是,一般请求某个 api 判断了能否需要登录就不会进入                        //假如进入可一做错误解决                        NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];                        userInfo[HTTPServiceErrorHTTPStatusCodeKey] = @(statusCode);                        userInfo[HTTPServiceErrorDescriptionKey] = @"请登录!";                                                NSError *noLoginError = [NSError errorWithDomain:HTTPServiceErrorDomain code:statusCode userInfo:userInfo];                                                FMHttpResonse *response = [[FMHttpResonse alloc] initWithResponseError:noLoginError code:statusCode msg:@"请登录!"];                        [subscriber sendNext:response];                        [subscriber sendCompleted];                        //错误提醒                        [self showMsgtext:@"请登录!"];                                            }else{                        NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];                        userInfo[HTTPServiceErrorResponseCodeKey] = @(statusCode);                        //取出服务给的提醒                        NSString *msgTips = responseObject[HTTPServiceResponseMsgKey];                        //服务器没有返回,错误信息                        if ((msgTips.length == 0 || msgTips == nil || [msgTips isKindOfClass:[NSNull class]])) {                            msgTips = @"服务器出错了,请稍后重试~";                        }                                                userInfo[HTTPServiceErrorMessagesKey] = msgTips;                        if (task.currentRequest.URL != nil) userInfo[HTTPServiceErrorRequestURLKey] = task.currentRequest.URL.absoluteString;                        if (task.error != nil) userInfo[NSUnderlyingErrorKey] = task.error;                        NSError *requestError = [NSError errorWithDomain:HTTPServiceErrorDomain code:statusCode userInfo:userInfo];                        //错误信息反馈回去了、可以在此做响应的弹窗解决,展现出服务器给我们的信息                        FMHttpResonse *response = [[FMHttpResonse alloc] initWithResponseError:requestError code:statusCode msg:msgTips];                                        [subscriber sendNext:response];                        [subscriber sendCompleted];                        //错误解决                        [self showMsgtext:msgTips];                    }                }            }        }];                /// 开启请求任务        [task resume];        return [RACDisposable disposableWithBlock:^{            [task cancel];        }];    }];    return [signal replayLazily]; //屡次订阅同样的信号,执行一次}

如何用:给一个简单的例子,也在项目中,介绍请git

- (IBAction)correctAction:(UIButton *)sender {    /// 1. 配置参数    NSMutableDictionary *easyDict = [NSMutableDictionary dictionary];    /// 2. 配置参数模型 #define MH_GET_LIVE_ROOM_LIST  @"Room/GetHotLive_v2"    FMHttpRequest *req = [FMHttpRequest urlParametersWithMethod:HTTTP_METHOD_POST path:@"Room/GetHotLive_v2" parameters:easyDict];            _reqSignal = [[FMARCNetwork sharedInstance] requestNetworkData:req];        [_reqSignal subscribeNext:^(FMHttpResonse *response) {        if (response.isSuccess) {            NSLog(@"--%@",response.reqResult);                        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:response.reqResult options:NSJSONWritingPrettyPrinted error:nil];                        NSString * str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];                        self.textV.text = str;        }            }];}
end@2x.png

首先感谢大家浏览此文章。
网络请求可以直接下载用:假如对您有帮助,请求点赞或者喜欢????,假如你有个github 账号,请不吝给??,谢谢。

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】在Qt中如何设置窗体的背景图片(2025-10-29 20:27)
【系统环境|】无声无名 | 杨·罗威斯终身回顾展(2025-10-29 20:26)
【系统环境|】从零开始学Qt(22):QSS详解(3)- 盒子模型(2025-10-29 20:25)
【系统环境|】Quarkus vs Spring Boot 集成 RabbitMQ 谁更香?(2025-10-29 20:24)
【系统环境|】RabbitMQ相关概念及代码示例(2025-10-29 20:24)
【系统环境|】Spring Boot + RabbitMQ:轻松掌握五种基本工作模式(2025-10-29 20:23)
【系统环境|】一篇文章带你彻底玩转-RabbitMQ(2025-10-29 20:22)
【系统环境|】私有云平台搭建——史上最详细(2025-10-29 20:21)
【系统环境|】RabbitMQ最全详解(万字图文总结)(2025-10-29 20:20)
【系统环境|】.Net/C#全网最火RabbitMQ操作【强烈推荐】(2025-10-29 20:20)
手机二维码手机访问领取大礼包
返回顶部