一,概述
做过Android开发的人员都知道,Google不但有系统自带的URLConnection和HttpClient来处理网络请求,而且还有好多开源的框架,比如Volley,OK3,Xutils等。
IOS作为另一个具有庞大开发者队伍的平台当然也不干落后,除了先后更新自己系统自带的网络框架NSURLConnection到NSURLSession,还有好多三方的,其中用户最多还在更新的就是AFNetworking了。
源码:https://github.com/XinRan5312/QXIOSHttp 欢迎Fork,这个小Demo封装了NSURLSession和AFNetWorking两个网络框架的使用
二,NSURLSession
NSURLSession是核心的管理类,通过NSURL,NSURLRequest(NSMutableURLRequest),还有一个最重要的网络处理策略配置类NSURLSessionConfiguration,包括配置缓存策略,Header和Cookie等,其中有三个类方法获得默认的NSURLSessionConfiguration。
当这一切都准备好以后NSURLSessionTask就该出场了,从名字大家就可以明白,他就是封装任务的,包括三个子类,NSURLSessionDataTask,NSURLSessionDownLoadTask,NSURLSessionUploadTask,从名字大家都是知道他们是干嘛的了,不过这只是封装任务,并没有开始执行任务,如果需要执行任务,需要[task resum],也可取消,停止任务,看如下实例代码:
@interfaceQXHTTPMenager()
@property(nonatomic,nullable)NSMutableDictionary<NSString*,NSURLSessionTask*> *taskDic;
@end
@implementation QXHTTPMenager
+(instancetype)ShareQXHTTPMenager{
staticQXHTTPMenager *sharedManager = nil;
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[selfalloc] init];
});
return sharedManager;
}
-(instancetype)init{
if([superinit]){
self.requestsDictionary=[[NSMutableDictionaryalloc]init];
self.baseUrl=@"http://www.baidu.com/";
returnself;
}else{
returnnil;
}
}
-(void)startRequest:(QXBaseRequest *)request{
if(request){
request.requestStatus=QXHTTPRequestStatusStart;
NSURL *url=[selfcreateNSURL:request];
if(url){
if(request.httpMethod){
QXHTTPMethod method=request.httpMethod;
NSMutableURLRequest *req=[NSMutableURLRequestrequestWithURL:url];
switch (method) {
caseQXHTTPMethodGet:
req.HTTPMethod=@"GET";
break;
caseQXHTTPMethodPost:
req.HTTPMethod=@"POST";
break;
caseQXHTTPMethodPut:
req.HTTPMethod=@"PUT";
break;
caseQXHTTPMethodPatch:
req.HTTPMethod=@"PATCH";
break;
caseQXHTTPMethodOptions:
req.HTTPMethod=@"OPTIONS";
break;
caseQXHTTPMethodDelete:
req.HTTPMethod=@"DELETE";
break;
caseQXHTTPMethodConnect:
req.HTTPMethod=@"CONNECT";
break;
caseQXHTTPMethodTrace:
req.HTTPMethod=@"TRACE";
break;
default:
req.HTTPMethod=@"GET";
break;
}
NSURLSession *session=[selfcreateNSURLSession:request];
NSURLSessionTask *task=[selfcreateURLSessionTask:session request:request nsRequest:req];
if(request.requestTag){
[task setTaskDescription:request.requestPath];
[_taskDicsetObject:task forKey:request.requestTag];
[self.requestsDictionarysetObject:request forKey:request.requestTag];
}
[task resume];
request.requestStatus=QXHTTPRequestStatusDoing;
}
}
}
}
-(NSURLSessionTask*)createURLSessionTask:(NSURLSession*) session request:(QXBaseRequest*)request nsRequest:(NSMutableURLRequest*) nsRequest{
NSURLSessionTask * task=nil;
QXHTTPReqeustType requestType=request.requestType;
if(requestType==QXHTTPReqeustTypeData){
task=[session dataTaskWithRequest:nsRequestcompletionHandler:^(NSData* data,NSURLResponse* response,NSError* error){
[selfhandleResponse:response data:dataerror:error request:request];
}];
}elseif(requestType==QXHTTPReqeustTypeUpLoadFiles){
task=[session uploadTaskWithRequest:nsRequestfromFile:[selfcreateNSURL:request] completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
[selfhandleResponse:response data:dataerror:error request:request];
}];
}elseif(requestType==QXHTTPReqeustTypeDownLoadFiles){
task=[session dataTaskWithRequest:nsRequestcompletionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
[selfhandleResponse:response data:dataerror:error request:request];
}];
}
return task;
}
-(void)handleResponse:(NSURLResponse*)response data:(NSData*)data error:(NSError*)error request:(QXBaseRequest*) request{
if(request.callback){
QXHTTPResponse *httpResponse=[[QXHTTPResponsealloc]init];
httpResponse.data=data;
httpResponse.response=response;
httpResponse.request=request;
httpResponse.error=error;
/**
NSJSONReadingOptions:
NSJSONReadingMutableContainers:返回可变容器,NSMutableDictionary或NSMutableArray。
NSJSONReadingMutableLeaves:返回的JSON对象中字符串的值为NSMutableString,目前在iOS 7上测试不好用,应该是个bug,参见:
http://stackoverflow.com/questions/19345864/nsjsonreadingmutableleaves-option-is-not-working
NSJSONReadingAllowFragments:允许JSON字符串最外层既不是NSArray也不是NSDictionary,但必须是有效的JSON Fragment。例如使用这个选项可以解析 @“123” 这样的字符串。
如果是0就是返回不了变的NSDictionary或者NSArray
注:其实我们用NSJSONSerialization也可以解析网络请求出来的的结果,只是它只是半自动
*/
NSDictionary *jsonObject=[NSJSONSerializationJSONObjectWithData:data options:NSJSONReadingMutableLeaveserror:nil];
[QXYYModeljson2Model:jsonObject model:request.responseReultObj];
request.callback(httpResponse);
// [NSJSONSerialization JSONObjectWithStream:<#(nonnull NSInputStream *)#> options:<#(NSJSONReadingOptions)#> error:<#(NSError * _Nullable __autoreleasing * _Nullable)#>];
if(error){
request.requestStatus=QXHTTPRequestStatusError;
}else{
request.requestStatus=QXHTTPRequestStatusFinished;
[_requestsDictionaryremoveObjectForKey:request.requestTag];
[_taskDicremoveObjectForKey:request.requestTag];
}
}
}
-(NSURLSession*)createNSURLSession:(QXBaseRequest*)request{
NSURLSession *session=nil;
switch (request.configType) {
caseQXHTTPConfigurationTypeDefault:
session=[NSURLSessionsessionWithConfiguration:request.configution.getDefaultConfigution];
break;
caseQXHTTPConfigurationTypeCustom:
session=[NSURLSessionsessionWithConfiguration:request.configution.customConfigution];
break;
caseQXHTTPConfigurationTypeOther:
session=[NSURLSessionsessionWithConfiguration:request.configution.customConfigution];
break;
default:
session=[NSURLSessionsessionWithConfiguration:request.configution.customConfigution];
break;
}
return session;
}
-(NSURL*)createNSURL:(QXBaseRequest*) request{
NSURL *nsUrl=nil;
if(request==nil)return nil;
if(request.requestPath){
NSString *url=[self.baseUrlstringByAppendingPathComponent:request.requestPath];
if(request.paramsDictionary){
[url stringByAppendingPathComponent:@"?"];
for (NSString* keyin [request.paramsDictionaryallKeys]) {
[url stringByAppendingString:[NSStringstringWithFormat:@"%@=%@&",key,[request.paramsDictionaryvalueForKey:key]]];
}
NSInteger len=[urllength];
NSRange rang=NSMakeRange(0, len-1);
url=[url substringWithRange:rang];
}
nsUrl=[NSURLURLWithString:url];
}else{
nsUrl=[NSURLURLWithString:self.baseUrl];
}
return nsUrl;
}
-(void)stopRequestByTag:(NSString *)tag{
QXBaseRequest *request=[self.requestsDictionaryvalueForKey:tag];
if(request){
NSURLSessionTask *task=[_taskDicvalueForKey:tag];
if(task&&[request.requestPathisEqualToString:[task taskDescription]]){
if(request.requestStatus==QXHTTPRequestStatusStart||request.requestStatus==QXHTTPRequestStatusDoing){
[task suspend];
request.requestStatus=QXHTTPRequestStatusStop;
if(request.stopBlock){
request.stopBlock(YES);
}
}
}
}
}
-(void)stopAllRequests{
for(NSString* tagin [self.requestsDictionaryallKeys]){
[selfstopRequestByTag:tag];
}
}
-(void)cancelRequestByTag:(NSString *)tag{
QXBaseRequest *request=[self.requestsDictionaryvalueForKey:tag];
if(request){
NSURLSessionTask *task=[_taskDicvalueForKey:tag];
if(task&&[request.requestPathisEqualToString:[task taskDescription]]){
if(request.requestStatus==QXHTTPRequestStatusStart||request.requestStatus==QXHTTPRequestStatusDoing||request.requestStatus==QXHTTPRequestStatusStop){
[task cancel];
request.requestStatus=QXHTTPRequestStatusNone;
if(request.cancelBlock){
request.cancelBlock(YES);
}
}
}
}
}
-(void)cancelAllRequests{
for(NSString* tagin [self.requestsDictionaryallKeys]){
[selfcancelRequestByTag:tag];
}
}
-(void)resumeTaskByTag:(NSString *)tag{
QXBaseRequest *request=[self.requestsDictionaryvalueForKey:tag];
if(request){
NSURLSessionTask *task=[_taskDicvalueForKey:tag];
if(task&&[request.requestPathisEqualToString:[task taskDescription]]){
if(request.requestStatus!=QXHTTPRequestStatusStart||request.requestStatus!=QXHTTPRequestStatusDoing){
[task resume];
request.requestStatus=QXHTTPRequestStatusStart;
}
}
}
}
-(void)resumeAllTasks{
for(NSString* tagin [self.requestsDictionaryallKeys]){
[selfresumeTaskByTag:tag];
}
}
-(void)clearAllRequest{
if(_requestsDictionary){
[_requestsDictionaryremoveAllObjects];
}
if(_taskDic){
[_taskDicremoveAllObjects];
}
}
@end
三,AFNetWorking
AFNetworking:https://github.com/AFNetworking/AFNetworking
他的核心类对比NSURLSession:
AFURLSessionManager和AFHTTPSessionManager对应NSURLSession但是功能更强大,请求的时候可以指定请求类型,回调的时候有NSProgress等,它返回的也是NSURLSessionTask对应几个子类,
AFNetWorking还有两个辅助的牛奔类:
1,AFURLRequestSerialization:封装请求类得到NSMutableURLRequest,需要url NSDictionary类型的参数,还有指定请求方法类型(GET,POST等),其实我们使用的时候都是使用它对应的子类,比如AFHTTPRequestSerialization,AFJSONRequestSerialization ,AFPropertyListRequestSerialization等
2,AFURLResoponseSerialization,用来指定解析的类型和验证数据的合法性(validateResponse),我们使用的时候也是使用它对应的子类,初始化的时候指给NSURLSessionManager就好,
_urlSessionManager.responseSerializer=[AFJSONResponseSerializerserializer];
还有:AFHTTPResponseSerialization,AFXMLParserResponseSerialization等,示例代码如下:
@interface QXAFNetworkTools()
@property(nonatomic,strong)AFURLSessionManager *urlSessionManager;
@property(nonatomic,strong)NSString *baseUrl;
@end
@implementation QXAFNetworkTools
-(instancetype)init{
if(self=[superinit]){
NSURLSessionConfiguration *config=[NSURLSessionConfigurationdefaultSessionConfiguration];
//设置Header
[config setHTTPAdditionalHeaders:@{@"User-Agent":@"qx&wr",@"Deveice":@"Android",@"Version":@"1.1.1"}];
//设置缓存大小
NSURLCache *urlCache=[[NSURLCachealloc]initWithMemoryCapacity:16*1024*1024diskCapacity:60*1024*1024diskPath:nil];
[config setURLCache:urlCache];
_urlSessionManager=[[AFURLSessionManageralloc]initWithSessionConfiguration:config];
//设置返回解析方式有好多种看源码
_urlSessionManager.responseSerializer=[AFJSONResponseSerializerserializer];
_baseUrl=@"";
returnself;
}else{
returnnil;
}
}
-(void)startRequest:(QXBaseRequest *)request{
if(request){
request.requestStatus=QXHTTPRequestStatusStart;
NSMutableURLRequest *urlRequest;
if(request.httpMethod){
QXHTTPMethod method=request.httpMethod;
NSString *reqMethod;
switch (method) {
caseQXHTTPMethodGet:
reqMethod=@"GET";
break;
caseQXHTTPMethodPost:
reqMethod=@"POST";
break;
default:
reqMethod=@"GET";
break;
}
urlRequest=[[AFHTTPRequestSerializerserializer] requestWithMethod:reqMethodURLString:[_baseUrlstringByAppendingPathComponent:request.requestPath]parameters:request.paramsDictionaryerror:nil];
NSURLSessionTask *task=[selfcreateURLSessionTask:request nsRequest:urlRequest];
if(request.requestTag){
// [task setTaskDescription:request.requestPath];
// [_taskDic setObject:task forKey:request.requestTag];
//
// [self.requestsDictionary setObject:request forKey:request.requestTag];
}
[task resume];
request.requestStatus=QXHTTPRequestStatusDoing;
}
}
}
-(NSURLSessionTask*)createURLSessionTask:(QXBaseRequest*)request nsRequest:(NSMutableURLRequest*) nsRequest{
NSURLSessionTask * task=nil;
QXHTTPReqeustType requestType=request.requestType;
if(requestType==QXHTTPReqeustTypeData){
task=[_urlSessionManagerdataTaskWithRequest:nsRequest uploadProgress:nildownloadProgress:nilcompletionHandler:^(NSURLResponse *response,id responseObject,NSError *error){
}];
}elseif(requestType==QXHTTPReqeustTypeUpLoadFiles){
task=[_urlSessionManageruploadTaskWithStreamedRequest:nsRequestprogress:nilcompletionHandler:^(NSURLResponse *_Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
}];
}elseif(requestType==QXHTTPReqeustTypeDownLoadFiles){
task=[_urlSessionManagerdownloadTaskWithRequest:nsRequestprogress:nildestination:^NSURL *_Nonnull(NSURL *_Nonnull targetPath, NSURLResponse *_Nonnull response) {
return targetPath;
} completionHandler:^(NSURLResponse *_Nonnull response, NSURL *_Nullable filePath, NSError *_Nullable error) {
}];
}
return task;
}
@end