AFNetworking 3.0 源码解析之Serialization
来源:互联网 发布:mrp格式软件下载 编辑:程序博客网 时间:2024/06/06 18:23
AFNetworking 3.0 源码解析之Serialization
本部分主要的作用:网络通信信息序列化/反序列化
一、AFURLRequestSerialization
功能:
负责参数转换成NSMutableURLRequest类型,进行网络请求。
1)构建普通请求:格式化请求参数,生成HTTP Header
2)构建multipart请求
类关系:
父类:AFHTTPRequestSerializer,二进制格式(query字符串转换成二进制)
子类:AFJSONRequestSerializer,Json格式(Json序列化成NSData类型)
AFPropertyListRequestSerializer,Plist(一种特殊的XML,解析起来相对容易)
封装思路:
所有类遵循一个协议AFURLRequestSerialization,协议中一个非必须实现的方法:
- (nullableNSURLRequest*)requestBySerializingRequest:(NSURLRequest*)request withParameters:(nullableid)parameters error:(NSError* _Nullable__autoreleasing *)error NS_SWIFT_NOTHROW;
父类AFHTTPRequestSerializer中提供外部调用接口:
- (NSMutableURLRequest*)requestWithMethod:(NSString*)method URLString:(NSString*)URLString parameters:(id)parameters error:(NSError*__autoreleasing*)error
在这个方法中调用协议方法:
mutableRequest = [[selfrequestBySerializingRequest:mutableRequestwithParameters:parameterserror:error]mutableCopy];
而这个方法的实现是父类以及各个子类分别实现。所以,此处self如果是AFHTTPRequestSerializer那么走AFHTTPRequestSerializer类下的实现,如果是
AFJSONRequestSerializer,那么走AFJSONRequestSerializer类下的实现。然后再分别实现这个方法不同功能的实现。
下面看一下各个类不同职能分别的实现:
AFURLRequestSerialization中的实现:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error{ NSParameterAssert(request); NSMutableURLRequest *mutableRequest = [requestmutableCopy]; [self.HTTPRequestHeadersenumerateKeysAndObjectsUsingBlock:^(id field,id value, BOOL *__unused stop) { if (![requestvalueForHTTPHeaderField:field]) { [mutableRequest setValue:valueforHTTPHeaderField:field]; } }]; NSString *query =nil; if (parameters) { if (self.queryStringSerialization) { NSError *serializationError; query = self.queryStringSerialization(request, parameters, &serializationError); if (serializationError) { if (error) { *error = serializationError; } returnnil; } } else { switch (self.queryStringSerializationStyle) { caseAFHTTPRequestQueryStringDefaultStyle: query = AFQueryStringFromParameters(parameters); break; } } } if ([self.HTTPMethodsEncodingParametersInURIcontainsObject:[[request HTTPMethod]uppercaseString]]) { //普通GET,HEAD等,参数直接拼接在url后面用&分开 if (query && query.length >0) { mutableRequest.URL = [NSURLURLWithString:[[mutableRequest.URLabsoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]]; } } else { // #2864: an empty string is a valid x-www-form-urlencoded payload if (!query) { query = @""; } if (![mutableRequestvalueForHTTPHeaderField:@"Content-Type"]) { [mutableRequest setValue:@"application/x-www-form-urlencoded"forHTTPHeaderField:@"Content-Type"]; } [mutableRequest setHTTPBody:[querydataUsingEncoding:self.stringEncoding]];// 普通的POST请求参数,直接转换成NSData设置到HTTP的body中。 } return mutableRequest;}我们可以看到AFNetworking对于GET,POST请求参数的处理,一个是直接拼接在URL上面,一个是设置在HTTPBody里面。
其中,HTTPMethodsEncodingParametersInURI的初始化如下:
self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil]; // 支持GET,HEAD,DELETE也就是GET,HEAD,DELETE支持的是参数直接拼接URL的方式。
AFJSONRequestSerialization中的实现:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error{ NSParameterAssert(request); if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { return [super requestBySerializingRequest:request withParameters:parameters error:error]; } NSMutableURLRequest *mutableRequest = [request mutableCopy]; [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { if (![request valueForHTTPHeaderField:field]) { [mutableRequest setValue:value forHTTPHeaderField:field]; } }]; // 设置公共的请求头 if (parameters) { if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; } [mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]]; } return mutableRequest;}OK,跟AFURLRequestSerialization中的实现差不多,如果是HTTPMethodsEncodingParametersInURI请求方式是GET,HEAD,DELETE,则直接调用父类的解析方法。如果是POST等其他的,那么做了一下设置请求头Content-Type = “application/json”,并且将paramters参数Json序列化成NSData,设置到HTTPBody里面。
AFPropertyListRequestSerialization中的实现:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error{ NSParameterAssert(request); if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { return [super requestBySerializingRequest:request withParameters:parameters error:error]; } NSMutableURLRequest *mutableRequest = [request mutableCopy]; [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { if (![request valueForHTTPHeaderField:field]) { [mutableRequest setValue:value forHTTPHeaderField:field]; } }]; if (parameters) { if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { [mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"]; } [mutableRequest setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]]; } return mutableRequest;}好吧,封装思路跟AFJSONRequestSerialization一样,区别在于json序列化变成Plist的转换。
二、AFURLResponseSerialization
功能:
负责对网络请求返回的数据进行解析。
类关系:
父类:AFHTTPResponseSerializer,二进制格式
子类:AFJSONResponseSerializer, JSON格式
AFXMLParseResponseSerializer, XML(只能返回XMLParser,还需要自己通过代理解析)
AFXMLDocumentResponseSerializer, (Mac OS X)
AFPropertyListResponseSerializer, Plist
AFImageResponseSerializer, Image
AFCompoundResponseSerializer, 组合
封装思路:
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error此处的返回值是id类型的,也就是数据解析完之后的数据。
顺便提一下返回值解析的调用函数是在AFURLSessionManager中的网络请求成功的回调中:
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error{#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wgnu" __strong AFURLSessionManager *manager = self.manager; __block id responseObject = nil; __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer; //Performance Improvement from #2672 NSData *data = nil; if (self.mutableData) { data = [self.mutableData copy]; //We no longer need the reference, so nil it out to gain back some memory. self.mutableData = nil; } if (self.downloadFileURL) { userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL; } else if (data) { userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data; } if (error) { userInfo[AFNetworkingTaskDidCompleteErrorKey] = error; dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{ if (self.completionHandler) { self.completionHandler(task.response, responseObject, error); } dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo]; }); }); } else { dispatch_async(url_session_manager_processing_queue(), ^{ NSError *serializationError = nil; responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError]; // 此处进行数据的解析 if (self.downloadFileURL) { responseObject = self.downloadFileURL; } if (responseObject) { userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject; } if (serializationError) { userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError; } dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{ if (self.completionHandler) { self.completionHandler(task.response, responseObject, serializationError); } dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo]; }); }); }); }#pragma clang diagnostic pop}
下面看一下各个类不同职能分别的实现:
父类AFHTTPResponseSerializer 中的实现:
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ [self validateResponse:(NSHTTPURLResponse *)response data:data error:error]; return data;}此处就一个方法,就是做了一个返回的数据是否有效。但是数据是否有错,都会返回原始数据,没有做任何的修改。
看一下返回数据有效性的方法实现:
- (BOOL)validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error{ BOOL responseIsValid = YES; NSError *validationError = nil; if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) { if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] && !([response MIMEType] == nil && [data length] == 0)) { if ([data length] > 0 && [response URL]) { NSMutableDictionary *mutableUserInfo = [@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]], NSURLErrorFailingURLErrorKey:[response URL], AFNetworkingOperationFailingURLResponseErrorKey: response, } mutableCopy]; if (data) { mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data; } validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError); } responseIsValid = NO; } if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) { NSMutableDictionary *mutableUserInfo = [@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode], NSURLErrorFailingURLErrorKey:[response URL], AFNetworkingOperationFailingURLResponseErrorKey: response, } mutableCopy]; if (data) { mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data; } validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError); responseIsValid = NO; } } if (error && !responseIsValid) { *error = validationError; } return responseIsValid;}这里主要做了判断是不是支持的返回content-type类型,再就是状态码是不是200+,如果不满足就不是有效的返回数据。
看下初始化值:
self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
子类AFJSONResponseSerializer中的实现:
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { return nil; } } id responseObject = nil; NSError *serializationError = nil; // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization. // See https://github.com/rails/rails/issues/1742 BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]]; if (data.length > 0 && !isSpace) { responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError]; } else { return nil; } if (self.removesKeysWithNullValues && responseObject) { responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions); } if (error) { *error = AFErrorWithUnderlyingError(serializationError, *error); } return responseObject;}此处看到在父类中对有效性的判断结果并没有做处理,而在Json转换类中,如果返回数据是无效的,直接就返回nil。然后就是对返回数据进行了Json转换。并对结果进行了空值进行了排空。
其他的子类的封装思路也都相似,不再一一赘述。注意的是不同的功能的子类对返回值的类型支持是不同的。
如果文中有什么错误,欢迎大家指正。
1 0
- AFNetworking 3.0 源码解析之Serialization
- AFNetworking源码之Serialization模块
- AFNetworking 3.0 源码解析之Reachability
- AFNetworking 3.0 源码解析之NSURLSession
- AFNetworking 3.0 源码解析之Reachability
- AFNetworking 源码解析之“AFURLSessionManager”
- AFNetworking源码解析<三>
- AFNetworking源码解析<三>
- AFNetworking源码解析<三>
- AFNetworking源码解析<四>
- AFNetworking源码解析<四>
- AFNetworking源码解析https
- AFNetworking源码解析<三>
- AFNetworking-源码解析
- AFNetworking源码解析<三>
- AFNetworking源码解析<四>
- AFNetworking源码解析<三>
- AFNetWorking源码解析
- 网站的一些状态提示
- lvs为何不能完全替代DNS轮询
- IOS开发记录用户登录状态
- Ceres-Solver库使用(一)--windows下安装配置
- leetcode刷题笔记-ZigZag Conversion
- AFNetworking 3.0 源码解析之Serialization
- Netty 之 浅析ByteToMessageDecoder
- 线性表(2)
- 入手Ticwatch2
- 算法导论(7)
- 学习oracle函数使用的笔记
- Jersey构建RESTful服务2--JAVA对象转成XML输出
- C - Wall
- 在Android中加载并使用opencv的方法