YTKNetwork网络封装

本人已迁移博客至掘进,以后会在掘进平台更新最新的文章也会有更多的干货,欢迎大家关注!!!https://juejin.im/user/588993965333309

 

本篇是答应在端午写iOS网络-四篇源码解析以及封装的最后一篇,是针对上一篇YTKNetwork源码解析后的一次封装,也是自己实际项目中所使用过的。在对YTKNetwork封装的时候,还是需要对YTKNetwork源码进行了解,方便对此封装的理解,请读一下:https://www.cnblogs.com/guohai-stronger/p/9194519.html

 本篇是实际工作过项目网络架构抽出来的,读完大约15-25分钟左右,Demo也会上传到github。(暂没有批量请求需求)

 

一、代码结构如下

1.针对YTKNetwork网络封装目录

2.项目代码结构与使用:举例购物车列表

 

二、准备

1.新建项目,导入AFNetworking,YTKNetwork(暂用cocoapods)。

1)通过命令行cd 新建项目地址(整个直接拖拽到终端),

2)进入项目输入vim Podfile

3)输入i,进入编辑模式

platform :ios, '8.0'

target 'TestYTK' do

  pod 'AFNetworking'
  pod 'YTKNetwork'
  pod 'YYModel'
  pod 'Toast'
  
end

4)然后按Esc键,并且输入“ :”号进入vim命令模式,在冒号后边输入wq

5)pod install

重新编译一下。 (最好建立一个pch文件,便于管理)

2.将代码直接拖入项目中

将标红的代码拖入项目中,编译一下!

 

三、代码分析

1 . IOANotificationManager(通知)

主要作用:主要是监听网络的变化。

#import <Foundation/Foundation.h>

extern const NSString *kNotNetworkNotificationKey;

@interface IOANotificationManager : NSObject

// 无网络
+ (void)postNoNetworkNotification:(NSDictionary *)userInfo;

// 无网络
+ (void)addNoNetworkBoserver:(id)target selector:(SEL)selector;

+ (void)removeObservers:(id)target;
@end

.m实现如下:

#import "IOANotificationManager.h"

const NSString *kNotNetworkNotificationKey = @"com.ioa.NoNetwork";

@implementation IOANotificationManager

+ (void)postNoNetworkNotification:(NSDictionary *)userInfo {
    [[NSNotificationCenter defaultCenter] postNotificationName:(NSString *)kNotNetworkNotificationKey object:nil userInfo:userInfo];
}


// 无网络
+ (void)addNoNetworkBoserver:(id)target selector:(SEL)selector {
    if (target) {
        [[NSNotificationCenter defaultCenter] addObserver:target selector:selector name:(NSString *)kNotNetworkNotificationKey object:nil];
    }
}

+ (void)removeObservers:(id)target {
    [[NSNotificationCenter defaultCenter] removeObserver:target];
}
@end

>>>拓展

其实在这里面也可以做用户登陆,退出登陆等监听操作。

 

2. IOARequest

主要作用:定义一些请求状态码、响应码,发起请求等

IOARequest.h

#import <YTKNetwork.h>
#import "IOAApiManager.h"
//管理用户信息
//#import "IOADataManager.h"
#import "IOANotificationManager.h"
#import "IOAResponse.h"

@interface IOARequest : YTKRequest

//返回接口状态码,其中:200 成功,
//                  600 未登录
//                  500 服务器错误
//                  501 已经存在
//                  502 数据接口为空
//                  400 请求参数有错,
//                  401 非法请求,
//                  1 没有网络
//                  0 服务后台问题,可使用response的statuscode查询具体问题

@property (nonatomic, readonly, assign) NSInteger serverResponseStatusCode;

//返回请求状态码,其中:1正常,0不正常
@property (nonatomic, readonly, assign) NSInteger serverRequestStatusCode;

// 返回的提示信息
@property (nonatomic, readonly, copy) NSString *serverResponseMessage;

// 如果没有网络 failure同步方式返回
- (void)startWithCompletionBlockWithSuccess:(YTKRequestCompletionBlock)success
                                    failure:(YTKRequestCompletionBlock)failure;

通过上面发现IOARequest是继承YTKRequest,以后我们在每一个模块请求数据的时候,就继承我们自己的IOARequest。

返回接口状态码以及请求码是根据我们后台自己定义的,大家可以根据自己的实际情况进行更改。

2. IOARequest.m

部分代码:

- (NSTimeInterval)requestTimeoutInterval {
    //请求限时
    return 30.0;
}

- (YTKRequestMethod)requestMethod {
    //测试环境,使用YTKRequestMethodGET,便于与后台和测试调试问题
#ifdef DEBUG
    return YTKRequestMethodGET;
#else
    return YTKRequestMethodPOST;
#endif

}


- (void)startWithCompletionBlockWithSuccess:(YTKRequestCompletionBlock)success
                                    failure:(YTKRequestCompletionBlock)failure {
    if (![IOAApiManager isNetworkReachable]) {
        self.serverResponseStatusCode = 1; // 没网络
        [IOANotificationManager postNoNetworkNotification:nil];
        if (failure) {
            failure(self);
        }
        return;
    }
    
//    WS(weakSelf);
    [self setCompletionBlockWithSuccess:success failure:^(__kindof YTKBaseRequest * _Nonnull request) {
        if (failure) {
            failure(request);
//            return;
        }

    }];
    
    //发起请求
    [self start];
}

- (BOOL)statusCodeValidator {
    //判断响应状态码
    BOOL isOk = [super statusCodeValidator];
    if (!isOk) {
#if DEBUG
        [self testAlertInfo:@"网络请求错误"];
#endif
        return isOk;
    }
    
    if (!self.responseObject) {
        self.serverResponseStatusCode = 0;
        return NO;
    }

    self.serverResponseStatusCode = [self.responseObject[@"ret"] integerValue];
    self.serverRequestStatusCode = [self.responseObject[@"code"] integerValue];
    self.serverResponseMessage = self.responseObject[@"msg"];
    
    if (self.serverResponseStatusCode == 200) {
        return YES;
    }
    else if (self.serverResponseStatusCode > 400 && self.serverResponseStatusCode < 500) {
        [IOAApiManager saveToken:nil];
        
        //移除用户个人信息
//        [IOADataManager removeUserInfo];
        
        return NO;
    }

    return NO;
}

 

3.IOAUploadRequest

主要负责:图片的上传和下载(我们项目上传图片,后台返回是一个对象,对象包括如下)。

#import "IOARequest.h"

// 上传图片返回的模型
@interface IOAUploadResponseModel : NSObject

@property (nonatomic, copy) NSString *url;

@property (nonatomic, copy) NSString *file;

@property (nonatomic, copy) NSString *file_name;

@end

//可以直接IOARequest,不需要继承YTKRequest
@interface IOAUploadRequest : IOARequest
@property (nonatomic, strong) UIImage *image;

//获取上传进度
@property(nonatomic, copy) void(^uploadProgressBlock)(IOAUploadRequest *currentApi, NSProgress * progress);
@end

在.m里面以文件上传方式上传

#define WS(weakSelf)  __weak __typeof(&*self)weakSelf = self

@implementation IOAUploadResponseModel

@end

@implementation IOAUploadRequest
- (YTKRequestMethod)requestMethod {
    return YTKRequestMethodPOST;
}

//设置上传图片 所需要的 HTTP HEADER
- (AFConstructingBlock)constructingBodyBlock {
    UIImage *image = self.image;
    return ^(id<AFMultipartFormData> formData) {
        NSData *data = UIImagePNGRepresentation(image);
        NSString *name = @"file";
        NSString *fileName = @"upload";
        NSString *type = @"image/png";
        [formData appendPartWithFileData:data name:name fileName:fileName mimeType:type];
    };
}
#pragma mark 上传进度
- (AFURLSessionTaskProgressBlock) resumableUploadProgressBlock {
    WS(weakSelf);
    AFURLSessionTaskProgressBlock block = ^void(NSProgress * progress){
        if (_uploadProgressBlock) {
            _uploadProgressBlock(weakSelf, progress);
        }
    };
    return block;
}
@end

 

4.IOANetworkManager

主要负责网络状态的管理,监听。

 

5.IOAResponse

主要负责后台返回状态码管理,包括:是否有网络,token是否失效,服务器错误以及参数错误等。

IOAResponse.h

typedef NS_ENUM(NSInteger, ResponseStatusType) {
    kResponseStatusTypeRequestError = 0, // 服务后台问题
    kResponseStatusTypeNoNetwork = 1, // 没有网络
    kResponseStatusTypeSuccess = 200,
    kResponseStatusTypeExpiryToken = 401,
    kResponseStatusTypeServerServiceError = 500,
//    kResponseStatustypeServiceExist = 501,
    kResponseStatusTypeDataNull = 502,
    kResponseStatusTypeNotLogin = 600,
};
@property (nonatomic, assign) BOOL success;
//返回接口状态码,其中:200 成功,
//                  600 未登录
//                  500 服务器错误
//                  501 已经存在
//                  502 数据接口为空
//                  400 请求参数有错,
//                  401 非法请求,
//                  1 没有网络
//                  0 服务后台问题,可使用response的statuscode查询具体问题
@property (nonatomic, assign) ResponseStatusType responseStatusType;
@property (nonatomic, assign) NSInteger serverResponseStatusCode; // 服务端返回的status code
@property (nonatomic, assign) NSInteger requestResponseStatusCode; // 请求返回的status code

@property (nonatomic, strong) id responseObject;

@property (nonatomic, copy) NSString *responseMessage;

+ (IOAResponse *)responseWithRequest:(IOARequest *)request;

- (void)updateStatusCodesWithRequest:(IOARequest *)request;

// 是否需要提示
- (BOOL)alertOrNot;
// 是否没有有网络
- (BOOL)isNoNetwork;

// 是否token失效
- (BOOL)isExpiryToken;

// 服务器错误
- (BOOL)isRequestServerError;

// 后台服务错误
- (BOOL)isServerServiceError;

IOAResponse.m是其赋值,查看demo即可。

 

6.IOAApiManager

主要任务:负责是管理Api,开发环境,证书,接口参数,token等。

IOAApiManager.h

+ (void)configNetwork;
//+ (NSString *)getService;
//+ (NSString *)getToken;
+ (NSMutableDictionary *)getCommomParametersWith:(NSString *)service token:(NSString *)token;
+ (NSMutableDictionary *)getParametersWithService:(NSString *)service;

+ (void)startNetworkMonitoring;
+ (void)stopNetworkMonitoring;
+ (BOOL)isNetworkReachable;
+ (AFNetworkReachabilityStatus)getNetworkStatus;

+ (void)saveToken:(NSString *)token;
+ (NSString *)getToken;

在IOAApiManager.m

typedef NS_ENUM(NSUInteger, ServerType) {
    kSeverTypeDev,     // 开发服务器地址
    kSeverTypeTest,     //测试服务器地址
    kSeverTypeRelease   //发布版服务器地址
};

@implementation IOAApiManager

+ (void)configNetwork {
    YTKNetworkAgent *agent = [YTKNetworkAgent sharedAgent];
    [agent setValue:[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain",@"application/x-www-form-urlencodem", nil] forKeyPath:@"_manager.responseSerializer.acceptableContentTypes"];
    
    static ServerType serverType = kSeverTypeRelease;

#if DEBUG
    serverType = kSeverTypeDev;
#else
    serverType = kSeverTypeRelease;
#endif
    
    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];
    switch (serverType) {
        case kSeverTypeDev:     // 开发服务器地址
            //改成自己的
            config.baseUrl = @"http://www.baidu.com";
            break;
        case kSeverTypeTest:     // 测试服务器地址
            config.baseUrl = @"https://www.baidu.com";
            break;
        case kSeverTypeRelease:   // 发布版服务器地址
            config.baseUrl = @"https://www.baidu.com";
            break;
        default:
            break;
    }
        
    [self configHttps];
}

+ (void)configHttps {
    
    // 获取证书
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ssl_content" ofType:@"pem"];//证书的路径
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    
    // 配置安全模式
    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];
    //    config.cdnUrl = @"";
    
    // 验证公钥和证书的其他信息
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    
    // 允许自建证书
    securityPolicy.allowInvalidCertificates = YES;
    
    // 校验域名信息
    securityPolicy.validatesDomainName = YES;
    
    // 添加服务器证书,单向验证;  可采用双证书 双向验证;
    securityPolicy.pinnedCertificates = [NSSet setWithObject:certData];
    
    [config setSecurityPolicy:securityPolicy];
}

上面的域名要改成自己的域名,上面是以baidu为准啦!!!

 

四、实际使用

1. 这个项目是以MVVM模式进行搭建。

在Api文件夹写接口参数

在viewModel里面写接口的请求以及解析

在Datas里面放的是plist文件等。

这样便于根据不同功能进行管理

 

2.Api文件夹

Api.h

Api.m,利用YYModel进行将声明的model转为字典,作为参数

 

3.ViewModel

ViewModel.h声明方法,请求方法

在ViewModel.m实现其方法

 

4.最后在控制器里面调用请求方法

4.1、导入ViewModel所在的类名

4.2、声明属性并懒加载

4.3、控制器调用请求方法

 

上面就是YTKNetwork的封装使用了,demo里面只有封装的代码,使用必须要真实的接口,(假数据没有必要)。如果有需要对YTKNetwork进行二次封装,可以下载github,然后按照这个使用方法就可以进行网络请求和封装啦。

demo地址:https://github.com/zxy1829760/YTKNetwork-

 

到现在为止,四天关于网络请求的内容四篇博客就大致说完了,欢迎大家指正!!!

posted @ 2018-06-19 18:10  国孩  阅读(6524)  评论(7编辑  收藏  举报