封装一个网络库的一些思路(基于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 <Foundation/Foundation.h>
#import <MJExtension/MJExtension.h>
@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返回的就是失败的字典喽!
整个封装大概就是这个思路,我这里纯粹是抛砖引玉,提供一个参考的封装方法,大家可以多多交流!收工!!!