封装项目网络库

封装一个网络库的一些思路(基于YTKNetwork)

为什么要封装网络库

大家都知晓网络层是一个项目的灵魂,所以网络层写的是否规范、是否简洁、是否完整关系到一个项目的整体质量,甚至于项目的性能。因此在这里我给大家分享下我是如何封装一个项目所用的网络库的(其实就是把整个项目所用的接口,写成一个库,方便项目使用)。

封装网络库的作用

1.请求数据
2.对每个接口都可以进行缓存时间设置
3.利用MJExtension进行字典模型转换
4.更加灵活方便的调用各个接口,降低了耦合性

如何封装

这里我列举一个用户登录的请求
首先基于YTKRequest封装一个SuperRequest类
@interface SuperRequestAPI : YTKRequest

@property (nonatomic, strong, readonly) YSNetworkConfig *config;

- (NSMutableDictionary *)signAndEncode:(NSMutableDictionary *)param;

- (void)printRequestInfo;

@end

@implementation SuperRequestAPI

- (NSMutableDictionary *)signAndEncode:(NSMutableDictionary *)params {
    NSMutableArray *paramArray = [[NSMutableArray alloc] init];
    
    NSArray *sortArray = [[params allKeys] sortedArrayUsingSelector:@selector(compare:)];
    
    for (NSString *key in sortArray) {
        NSString *param = [NSString stringWithFormat:@"%@", [params objectForKey:key]];
        if (param && ![param isEqualToString:@""]) {
            [paramArray addObject:param];
        }
    }
    
    // 获取加密字符串
    NSString *encode = [YSSecurityHelper getEncodePostMsgDataWithParams:paramArray encodeKey:self.config.encodeKey];
    
    // 将加密字符串作为参数上传
    [params setObject:encode forKey:@"sign"];
    return params;
}

#pragma mark - 配置信息
- (YTKRequestMethod)requestMethod {
    return YTKRequestMethodPost;
}

- (NSString *)baseUrl {
    return self.config.serviceURL;
}


- (NSTimeInterval)requestTimeoutInterval {
    return 30;
}

- (NSInteger)cacheTimeInSeconds {
    return kCacheTime;
}

- (void)printRequestInfo {
    NSMutableString *requestString = [[NSMutableString alloc] init];
    [requestString appendString:self.baseUrl];
    [requestString appendString:self.requestUrl];
    
    NSArray *sortArray = [[self.requestArgument allKeys] sortedArrayUsingSelector:@selector(compare:)];
    
    for (NSString *key in sortArray) {
        [requestString appendString:@"&"];
        [requestString appendString:key];
        [requestString appendString:@"="];
        [requestString appendString:self.requestArgument[key]];   
    }
    
    NSLog(@"请求地址:==========%@", requestString);
}

这个类可以对请求参数进行签名和加密、设置缓存时间、打印请求地址等等一些操作。

创建一个LoginRequestAPI类继承SuperRequestAPI
#import "SuperRequestAPI.h"

@interface LoginRequestAPI : SuperRequestAPI

/**
 *  @brief  登录请求参数
 *
 *  @param userName 用户名
 *  @param password 密码
 *
 *  @return LoginRequestModel
 */
- (id)initWithUserName:(NSString *)userName password:(NSString *)password;
@end



#import "LoginRequestAPI.h"

@interface LoginRequestAPI ()

@property (nonatomic, strong) NSString *userName;
@property (nonatomic, strong) NSString *password;
// 设置请求参数
@property (nonatomic, strong) NSMutableDictionary *requestParam;

@end

@implementation LoginRequestAPI

- (id)initWithUserName:(NSString *)userName password:(NSString *)password {
    
    if (self = [super init]) {
        _userName  = userName;
        _password = password;
    }
    return self;
}

#pragma mark - Getter && Setter
- (NSMutableDictionary *)requestParam {
    if (_requestParam == nil) {
        
        /** 赋值参数字段 */
        _requestParam = [[NSMutableDictionary alloc] init];
       
        [_requestParam setObject:(_userName ? _userName : @"") forKey:@"userName"];
        [_requestParam setObject:(_password ? _password : @"") forKey:@"password"];
        
        //对参数进行签名和加密处理
        _requestParam = [self signAndEncode:_requestParam];
    }
    return _requestParam;
}

#pragma mark - 配置请求信息

- (id)requestArgument {
    return self.requestParam;
}

@end

在这个请求参数类里面你可以设置你的请求路径,版本号、请求参数等等。完整的封装了请求参数,需要的话可以对参数进行签名和加密处理。

创建相应的模型类

这里我们用到MJExtension进行字典模型转换,对字段进行了一一映射处理,MJExtension具体用法请参考https://github.com/CoderMJLee/MJExtension

#import 
#import 

@interface LoginDetail : NSObject

@property (nonatomic, strong) NSString *mAuthCode;
@property (nonatomic, strong) NSString *mAvatar;
@property (nonatomic, strong) NSString *mCae;
@property (nonatomic, strong) NSString *mId;
@property (nonatomic, strong) NSString *mIsThird;
@property (nonatomic, strong) NSString *mLastLoginTime;
@property (nonatomic, strong) NSString *mPassId;
@property (nonatomic, strong) NSString *mToken;
@property (nonatomic, strong) NSString *mUsername;
@property (nonatomic, strong) NSString *mValidate;

@end

#import "LoginDetail.h"

@implementation PhoneLoginDetail

+ (NSDictionary *)replacedKeyFromPropertyName {
    return @{
             @"mAuthCode" : @"auth_code",
             @"mAvatar" : @"avatar",
             @"mCae" : @"cae",
             @"mId" : @"id",
             @"mIsThird" : @"is_third",
             @"mLastLoginTime" : @"last_login_time",
             @"mPassId" : @"passid",
             @"mToken" : @"token",
             @"mUsername" : @"username",
             @"mValidate" : @"validate"
             };
}
@end

最后一步,就是写请求接口类了

这个类里面可以把所有的请求接口写进去,最好用类方法。

@interface YBNetwork : NSObject
+ (void)requestLoginDetailWithUserName:(NSString *)userName
                                   password:(NSString *)password
                                    success:(void (^)(LoginDetail * LoginDetail, BOOL success, NSDictionary *responseObject))successBlock
                                    failure:(void (^)(NSDictionary *requestParam))failureBlock;
@end


@implementation YBNetwork

/*!
 *  请求用户登录信息
 *  @param userName    用户名
 *  @param password    密码
 *  @param successBlock 成功block
 *  @param failureBlock 失败block
 */
+ (void)requestLoginDetailWithUserName:(NSString *)userName
                                   password:(NSString *)password
                                    success:(void (^)(LoginDetail * LoginDetail, BOOL success, NSDictionary *responseObject))successBlock
                                    failure:(void (^)(NSDictionary *requestParam))failureBlock {
    
    [YBNetwork addAcceptableContentTypes];
    
    LoginRequestAPI *api = [[LoginRequestAPI alloc] initWithUserName:userName password:password];;
    
    [api startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest *request) {
        NSDictionary *responseDictionary = [request responseJSONObject];
        NSString *status;
        if (DATA_STRING(responseDictionary[@"status"])) status = responseDictionary[@"status"];
        if (200 == status.integerValue) {
            if (DATA_DICTIONARY(responseDictionary[@"info"])) {
                NSDictionary *info = responseDictionary[@"info"];
                LoginDetail *phoneLoginDetail = [LoginDetail mj_objectWithKeyValues:info];
                // 请求成功
                successBlock(phoneLoginDetail, YES, responseDictionary);
            } else {
                // 返回数据格式存在问题
                successBlock(nil, YES, responseDictionary);
            }
        } else {
            // 返回的status非法
            successBlock(nil, NO, responseDictionary);
        }
    } failure:^(__kindof YTKBaseRequest *request) {
        // 网络请求失败
        failureBlock(request.requestArgument);
    }];
    [api printRequestInfo];
}

这里我的一个思路是基于YTKNetwork写这个接口,采用block回调形式,回调两个参数,一个是success和failure,success返回模型实例对象,success布尔值以及返回json转换后的字典,之所以还返回字典是便于项目中调试接口用。failure返回的就是失败的字典喽!
整个封装大概就是这个思路,我这里纯粹是抛砖引玉,提供一个参考的封装方法,大家可以多多交流!收工!!!

你可能感兴趣的:(封装项目网络库)