写在前面:对于移动端开发来说,无论iOS,Android,抑或是H5开发,所谓的开发核心之一就是从服务端接收数据,前端负责展示,所以,当然还有各种逻辑的实现,但是呢,一个完善的APP肯定是少不了与服务端交互的,所以一个网络请求类的封装好用与否直接关系到一个项目的开发效率以及后期的维护,本人也接手过那种没有请求类的项目呢,每个请求写了一堆代码,用的全部是ASI,,然后需要更改为AFN的时候,哇,简直无敌了,然后Command+F都用不上,只能一处处找,找的自己都不知道时间了,真的相当折磨,受过这个折磨的童鞋肯定能够体会这种痛苦,有种删除项目,拍屁股走人的邪恶想法,但是呢,毕竟咱的职业素养还在,所以就耐心的享受这折磨了.废话不多说,相信每个开发的童鞋都能知道一个好的网络请求类带给我们的便捷之处.
** 1.Swift3.0**
不用过多介绍什么,Swift是苹果主推的开发语言,老司机都知道原来是OC,Swift语言笔者前天花了一下午+一晚上的时间学习了下,确实很简洁,开发速度确实很快,风格类似于(JS+Python)我比较喜欢的是Swift中的泛型,泛型这个东西Java中有,当初写Java的时候泛型真的让我方便了很多很多,所以在进行iOS开发的时候一直琢磨着有没有泛型这个东西,可是呢,都知道没有...最近安卓新出的kotlin语言,跟Swift也是大同小异吧.
** 2.AFN**
AFN是一套iOS网络请求框架,用OC语言编写(我记得原来有Swift语言编写的,但是去GitHub上找的时候没有找到)这个框架现在几乎所有的iOS项目都在用吧,确实很好用,当然不缺乏大牛公司自己封装的,当然也可能有老项目还在用ASI(曾经火了好长时间,但是现在没人用了,WHy?因为作者不更新了...可悲不)
** 3.MJExtention**
MJExtention是李明杰大神的一套框架,主要用来字典转模型,这个框架的好用程度本人给100分,当然还有别的功能,其他的童鞋们慢慢去挖掘吧.即便你的对象里包含对象数组,它也可以帮你全部转换的哦,有不懂的或者有兴趣的可以直接去GitHub上下载学习一下,或者给我留言也可以哦.
4.封装思想
我也相信这些封装思想应该很多人都知道了,思想就像风暴一样,瞬间可以席卷全球,真是个神奇的东西,当然我的这个也是来源于网络上大神的分享.
AFN的源码我看了一遍,我们可以直接用AFHTTPSessionManager,有兴趣的童鞋可以研究下AFN的源码,然后我的想法是继承AFHTTPSessionManager创建一个RequsetManager类,(当然第一版我用的是装饰模式,是在RequsetManager中装饰一个AFHTTPSessionManager对象,当然两种方法各有各的优点,直接继承可能调用方法上更加简洁一点,然后也会减少一个对象的使用...)提供一个RequsetManager单例,然后创建一个NetworkService类,为所有的请求提供服务,在这个里面使用包装RequsetManager,使用RequsetManager下载数据,在NetworkService中提供对数据的解密,缓存(当然我没有去实现缓存的功能),以及对数据的解析转换(MJExtention在这儿真的起了很大的作用--在此转换数据的时候我们需要知道将json数据转换为什么样的对象,在OC版本中实现的时候我们是将要转换对象的Class当做参数传了过去,但是返回的结果是id的,我们用的时候需要进行强转,但是在Swift中我们有了泛型,所以这一步就简洁了很多,具体的祥看代码,后面会同样奉上OC版本的封装).
5.OC版本
RequsetManager:仅仅实现了Post和GET方法,声明了成功和失败的Block回调,一个重新载入请求头的,当然大部分是没有用的,另外一个是获取单利的,但是,所有的方法均是静态方法,获取单利是可以在外部单独设置请求头
#import "AFHTTPSessionManager.h"
typedef void (^requestSuccessBlock)(id responseObj);
typedef void (^requestFailureBlock) (NSError *error);
@interface RequsetManager : AFHTTPSessionManager
+ (instancetype)sharedRequestManager;
+ (void)AFN_ReloadHeaderAuth;
+ (void)AFN_GetRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler;
+ (void)AFN_PostRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler;
@end
实现如下:
#import "RequsetManager.h"
@interface RequsetManager()
@end
@implementation RequsetManager
+ (instancetype)sharedRequestManager{
static dispatch_once_t onceToken;
static RequsetManager * manager = nil;
dispatch_once(&onceToken, ^{
manager = [[self alloc]init];
manager.requestSerializer.timeoutInterval = 60.0f;
[manager.requestSerializer setValue:@"" forHTTPHeaderField:@"jwttoken"];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
});
return manager;
}
+ (void)AFN_ReloadHeaderAuth{
[[[self sharedRequestManager] requestSerializer] setValue:@"" forHTTPHeaderField:@"jwttoken"];
}
+ (void)AFN_GetRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler{
[[self sharedRequestManager] GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successHandler(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failureHandler(error);
}];
}
+ (void)AFN_PostRequest:(NSString *)url params:(NSDictionary *)params success:(requestSuccessBlock)successHandler failure:(requestFailureBlock)failureHandler{
[[self sharedRequestManager] POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successHandler(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failureHandler(error);
}];
}
@end
RequestService:仅仅封装了返回结果为JSON的,其实有XMLDictionary可以将XML转换为JSON的,有兴趣的可以从后面我的GitHub上下载demo ,里面包含了这个类,当然也可以直接从GitHub上搜索
#import <Foundation/Foundation.h>
typedef void (^responseResultBlock)(id dataObj, NSError *error);
@interface RequestService : NSObject
/**
重新载入请求头
*/
+ (void)reloadAFNHeaderAuth;
/**
利用AFN请求获取JSON返回 --- GET请求
@param url 请求地址
@param param 请求参数
@param modelClass 请求返回所需要转换的模型类
@param responseBlock 请求成功|失败回调
*/
+ (void)AFN_JSONResponseGetWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock) responseBlock;
/**
利用AFN请求获取JSON返回 --- POST请求
@param url 请求地址
@param param 请求参数
@param modelClass 请求返回所需要转换的模型类
@param responseBlock 请求成功|失败回调
*/
+ (void)AFN_JSONResponsePostWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock)responseBlock;
/**
请求返回结果转换为模型方法 -- 此方法不需要关注,如果有Service继承此类,可以重写该方法进行数据处理
@param responseObj 返回结果
@param modelClass 模型类
@return 转换成功的模型
*/
+ (id)modelTransformationWithResponseObj:(id)responseObj modelClass:(Class)modelClass;
@end
具体实现如下:
#import "RequestService.h"
#import "RequsetManager.h"
#import "MJExtension.h"
static id dataObj;
@implementation RequestService
+ (void)reloadAFNHeaderAuth{
[RequsetManager AFN_ReloadHeaderAuth];
}
+ (void)AFN_JSONResponseGetWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock) responseBlock{
[RequsetManager AFN_GetRequest:url params:param success:^(id responseObj) {
dataObj = [self modelTransformationWithResponseObj:responseObj modelClass:modelClass];
responseBlock(dataObj,nil);
} failure:^(NSError *error) {
responseBlock(nil,error);
}];
}
+ (void)AFN_JSONResponsePostWithUrl:(NSString *)url param:(id)param modelClass:(Class)modelClass responseBlock:(responseResultBlock)responseBlock{
[RequsetManager AFN_PostRequest:url params:param success:^(id responseObj) {
dataObj = [self modelTransformationWithResponseObj:responseObj modelClass:modelClass];
responseBlock(dataObj,nil);
} failure:^(NSError *error) {
responseBlock(nil,error);
}];
}
+ (id)convertJson:(NSString *)jsonStr
{
if (!jsonStr) {
return nil;
}
NSError * error;
return [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:&error];
}
/**
解密
@param response 网络数据
@return 解密结果
*/
+ (NSString *)decreptResponse:(NSString *)response{
return response;
}
+ (id)modelTransformationWithResponseObj:(id)responseObj modelClass:(Class)modelClass{
NSString *response = [[NSString alloc] initWithData:(NSData *)responseObj encoding:NSUTF8StringEncoding];
response = [self decreptResponse:response];
id tmp = [self convertJson:response];
if ([tmp isKindOfClass:[NSArray class]]) {
return [modelClass mj_objectArrayWithKeyValuesArray:responseObj];
}else if([tmp isKindOfClass:[NSDictionary class]]){
return [modelClass mj_objectWithKeyValues:responseObj];
}
return nil;
}
@end
6.Swift版本
import Foundation
/// 请求工具类
class NetworkService{
/// Get 请求
///
/// - Parameters:
/// - url: 请求地址
/// - params: 请求参数
/// - complete: 请求回调 -- 回传结果为对象
static func GetRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModel:T?,_ error:Error?)->()){
RequsetManager.getRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultObj,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// Get请求
///
/// - Parameters:
/// - url: 请求地址
/// - params: 请求参数
/// - complete: 请求完成回调 -- 回传结果为对象数组
static func GetRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModelArray:[T]?,_ error:Error?)->()){
RequsetManager.getRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultArr,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// Post 请求
///
/// - Parameters:
/// - url: 请求地址
/// - params: 请求参数
/// - complete: 请求回调 -- 回传结果为对象
static func PostRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModel:T?,_ error:Error?)->()){
RequsetManager.postRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultObj,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// Post请求
///
/// - Parameters:
/// - url: 请求地址
/// - params: 请求参数
/// - complete: 请求完成回调 -- 回传结果为对象数组
static func PostRequest<T:NSObject>(url:String,
params:[String:AnyObject]?,
complete:@escaping (_ dataModelArray:[T]?,_ error:Error?)->()){
RequsetManager.postRequest(url: url, params: params, success: { (result) in
self.transformModel(result: result, complete: { (resultObj:T?,resultArr:[T]?) in
complete(resultArr,nil)
})
}) { (error) in
complete(nil,error)
}
}
/// 转换方法
///
/// - Parameters:
/// - result: 网络返回数据
/// - complete: 转换完成回调
static func transformModel<T:NSObject>(result:Any?,
complete:@escaping (_ result:T?,_ resultArray:[T]?)->()){
let jsonStr = self.converNetData(result: result as Any)
let obj = T.mj_object(withKeyValues: jsonStr)
var objArr = [T]()
if T.mj_objectArray(withKeyValuesArray: jsonStr) != nil {
for item in T.mj_objectArray(withKeyValuesArray: jsonStr) {
objArr.append(item as! T)
}
}
complete(obj,objArr)
}
/// 转换网络数据
///
/// - Parameter result: 网络数据
/// - Returns: 返回结果
static func converNetData(result:Any) -> String{
let respose = String.init(data: result as! Data, encoding: String.Encoding.utf8)
return self.decreptRespose(respose: respose)
}
/// 解密
///
/// - Parameter respose: 网络数据
/// - Returns: 解密结果
static func decreptRespose(respose:String?) -> String{
//自己实现解密
return respose ?? "{}"
}
}
/// 请求管理
class RequsetManager :AFHTTPSessionManager {
/// 初始化RequsetManager单利
static let sharedRequestManager:RequsetManager = {
let instance = RequsetManager()
instance.requestSerializer.timeoutInterval = 60.0
//自定义设置请求头
// instance.requestSerializer.setValue(<#T##value: String?##String?#>, forHTTPHeaderField: <#T##String#>)
instance.responseSerializer = AFHTTPResponseSerializer()
return instance
}()
/// GET请求
///
/// - Parameters:
/// - url: 请求地址
/// - params: 请求参数
/// - success: 请求成功回调
/// - failure: 请求失败回调
static func getRequest(url:String,
params:[String:AnyObject]?,
success:@escaping (_ responseData:Any?)->()?,
failure:@escaping (_ error:Error)->()?){
RequsetManager.sharedRequestManager.get(url, parameters: params, progress: nil, success: {
(task:URLSessionDataTask,result:Any?) in
success(result)
}) { (task:URLSessionDataTask?, error:Error) in
failure(error)
}
}
/// POST请求
///
/// - Parameters:
/// - url: 请求地址
/// - params: 请求参数
/// - success: 请求成功回调
/// - failure: 请求失败回调
static func postRequest(url:String,
params:[String:AnyObject]?,
success:@escaping (_ responseData:Any?)->()?,
failure:@escaping (_ error:Error)->()?){
RequsetManager.sharedRequestManager.post(url, parameters: params, progress: nil, success: {
(task:URLSessionDataTask,result:Any?) in
success(result)
}) { (task:URLSessionDataTask?, error:Error) in
failure(error)
}
}
}
7.对比--使用--分析
Swift版本其实就是对OC版本的一个更改在RequsetManager层次几乎是一样的,在Service层,OC版本需要在使用的时候将所要转换的对象的Class当做参数传过来,而在Swift版本中,仅仅需要在闭包中用泛型就可以,无需再需要传递对象的类
在使用上,OC版本回调回去的是一个id对象,无论是对象数组抑或是对象,都需要强制转换后使用,而在Swift版本中,我用了多态的性质,根据使用时传递的闭包不同,返回的结果也不同,结果是对象的和结果是对象数组的,可以分别选择调用相对应的方法.
使用
返回结果是对象的OC版本:
- (void)test1{
[RequestService AFN_JSONResponseGetWithUrl:@"http://192.168.1.107:8080/SkeeterTask/test/login" param:nil modelClass:[TestModel class] responseBlock:^(id dataObj, NSError *error) {
if (error) {
return ;
}
//使用上需要将id类型的dataObj进行强转...
NSLog(@"结果为对象---%@",((TestModel *)dataObj).message);
}];
}
返回结果是对象数组的OC版本:
[RequestService AFN_JSONResponseGetWithUrl:@"http://192.168.1.107:8080/SkeeterTask/test/login2" param:nil modelClass:[TestModel class] responseBlock:^(id dataObj, NSError *error) {
if (error) {
return ;
}
//此时没必要强制转换,如果网络数据返回的是数组,得到的dataObj肯定是数组
而且里面的对象肯定是传的modelClass对象
for (TestModel * mode in dataObj) {
NSLog(@"结果为对象数组--%@",mode.message);
}
}];
返回结果是对象的Swift版本
NetworkService .GetRequest(url: "http://192.168.1.107:8080/SkeeterTask/test/login", params: nil) { (model:TestModel?, error:Error?) in
if error != nil {
print("Error")
return
}
//调用方法的时候TestModel是当做泛型传递过去的,所以回调的model
是可以直接来使用的
print("结果为对象--->\(model?.message ?? "NoMessage")")
}
返回结果是对象数组的Swift版本
NetworkService.GetRequest(url: "http://192.168.1.107:8080/SkeeterTask/test/login2", params: nil) { (modelArr:[TestModel]?, error:Error?) in
if error != nil{
print("Error")
return
}
//运用传递的闭包不同,返回的modelArr的泛型为TestModel
所以返回过来之后可以直接使用了
if let arr = modelArr{
for item in arr{
print("结果为对象数组--->\(item.message ?? "NoMessage")")
}
}
}
分析,这两中其实思想是一样的,只不过Swift版本因为使用了泛型,所以在使用的时候更加清晰,而且也不需要将所要转换的对象类当做参数进行传递,而且使用了多态,根据返回的结果不同分别传递不同的闭包,而OC版本,始终都是那一个方法,需要对返回的结果进行强制转换,所以使用起来没有那么的一目了然,大致就是这样,希望我这个可以抛砖引玉,有好的想法的童鞋可以给我留言交流,共同提高
8.写在最后
最后提醒一下,我请求的地址是我使用Java写的本地的一个服务,小伙伴们在使用的时候可要进行相对应的更改哦,最后奉上我测试的结果截图,有什么不足呢,可以给我留言沟通共同提高哦.谢谢
10.最后的最后,奉上完整的Demo地址(XML转JSON的类在OC源码中)