Serialization 包括 AFURLResponseSerialization 和 AFURLRequestSerialization
AFURLResponseSerialization 是处理响应的模块,将请求返回的数据解析成对应的格式。而AFURLRequestSerialization的主要作用是修改请求(主要是 HTTP 请求)的头部,提供了一些语义明确的接口设置 HTTP 头部字段。
AFURLResponseSerialization
AFURLResponseSerialization 是一个协议,协议的内容为:
1 2 3
   | - (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response                            data:(nullable NSData *)data                           error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
   | 
 
它的实现类为:
- AFURLResponseSerialization
- AFHTTPResponseSerializer
- AFJSONResponseSerializer
 
- AFXMLParserResponseSerializer
 
- AFXMLDocumentResponseSerializer
 
- AFPropertyListResponseSerializer
 
- AFImageResponseSerializer
 
- AFCompoundResponseSerializer
 
 
 
在文件中 所有类都遵循AFURLResponseSerialization,而AFHTTPResponseSerializer是其他类的基类。
AFHTTPResponseSerializer
初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | + (instancetype)serializer {     return [[self alloc] init]; }
  - (instancetype)init {     self = [super init];     if (!self) {         return nil;     }
      self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];     self.acceptableContentTypes = nil;
      return self; }
  | 
 
因为是对 HTTP 响应进行序列化,所以这里设置了 stringEncoding 为 NSUTF8StringEncoding 而且没有对接收的内容类型加以限制。
将 acceptableStatusCodes 设置为从 200 到 299 之间的状态码, 因为只有这些状态码表示获得了有效的响应。
验证响应的有效性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | - (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]]) { 			#1: 返回内容类型无效         }
          if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) { 			#2: 返回状态码无效         }     }
      if (error && !responseIsValid) {         *error = validationError;     }
      return responseIsValid; }
   | 
 
这个方法根据在初始化方法中初始化的属性 acceptableContentTypes 和 acceptableStatusCodes 来判断当前响应是否有效。
AFURLResponseSerialization协议的实现
1 2 3 4 5 6 7 8
   | - (id)responseObjectForResponse:(NSURLResponse *)response                            data:(NSData *)data                           error:(NSError *__autoreleasing *)error {     [self validateResponse:(NSHTTPURLResponse *)response data:data error:error];
      return data; }
   | 
 
调用上面的方法对响应进行验证,然后返回数据
AFJSONResponseSerializer
初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | + (instancetype)serializer {     return [self serializerWithReadingOptions:(NSJSONReadingOptions)0]; }
  + (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions {     AFJSONResponseSerializer *serializer = [[self alloc] init];     serializer.readingOptions = readingOptions;
      return serializer; }
  - (instancetype)init {     self = [super init];     if (!self) {         return nil;     }
      self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];
      return self; }
  | 
 
相对AFHTTPResponseSerializer 设置了acceptableContentTypes;
AFURLResponseSerialization协议的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | - (id)responseObjectForResponse:(NSURLResponse *)response                            data:(NSData *)data                           error:(NSError *__autoreleasing *)error { 	1. 验证请求
  	2. 解决一个由只包含一个空格的响应引起的 bug
  	3. 序列化 JSON 	 	4. 移除 JSON 中的 null
      if (error) {         *error = AFErrorWithUnderlyingError(serializationError, *error);     }
      return responseObject; }
   | 
 
1. 验证请求
1 2 3 4 5
   | if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {         if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {             return nil;         }     }
  | 
 
调用自身的validateResponse验证响应,
validateResponse:中如果content-type不满足,那么产生的validationError就是Domain为AFURLResponseSerializationErrorDomain,code为NSURLErrorCannotDecodeContentData,再用 AFErrorOrUnderlyingErrorHasCodeInDomain检验error 和domain,如果就是这两个值 就返回nil。
2. 解决一个由只包含一个空格的响应引起的 bug
1 2 3 4 5
   | BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
  if (data.length == 0 || isSpace) {     return nil; }
   | 
 
对于’head :ok’,Rails返回的是一个空格 (这是Safari上的一个bug),并且这样的JSON格式不会被NSJSONSerialization解析。如果是单个空格,就不解析
查看 Issues 1742
3.序列化 JSON
1 2 3 4 5 6 7 8 9 10 11
   | NSError *serializationError = nil;
  id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
  if (!responseObject) {     if (error) {         *error = AFErrorWithUnderlyingError(serializationError, *error);     }     return nil; }
   | 
 
使用系统自带的NSJSONSerialization来解析NSData数据,如果serializationError不为空,那么最终的error其实就是serializationError
4. 移除 JSON 中的 null
1 2 3
   | if (self.removesKeysWithNullValues) {     return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions); }
  | 
 
AFJSONObjectByRemovingKeysWithNullValues通过递归的方法,把JSON中NSDictionary的数据(不包括NSArray)中的对应value为空的key移除。
AFURLRequestSerialization
AFURLRequestSerialization 的主要工作是对发出的 HTTP 请求进行处理。
使用
1 2 3 4 5
   | [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:parameters error:nil];
  [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters error:nil];
  [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters error:nil];
   | 
 
AFURLRequestSerialization
AFURLRequestSerialization 是一个协议
1 2 3 4
   | - (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request                                withParameters:(nullable id)parameters                                         error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
 
   | 
 
它的实现类为:
- AFURLRequestSerialization
- AFHTTPRequestSerializer
- AFJSONRequestSerializer
 
- AFPropertyListRequestSerializer
 
 
 
AFHTTPRequestSerializer是所有类的基类,AFJSONRequestSerializer 和 AFPropertyListRequestSerializer继承了AFHTTPRequestSerializer。
AFHTTPRequestSerializer
初始化:
1 2 3 4 5 6 7 8 9
   | + (instancetype)serializer {     return [[self alloc] init]; }
  - (instancetype)init{ 	1. 初始化参数,  	2. 设置HTTP 头部字段 	3. KVO }
  | 
 
1. 初始化参数
1 2 3 4 5 6 7 8
   |  self.stringEncoding = NSUTF8StringEncoding; self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary]; self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
  self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil]; self.mutableObservedChangedKeyPaths = [NSMutableSet set];
 
 
  | 
 
初始化了一些参数 ,HTTPMethodsEncodingParametersInURI表示需要将的quey是拼接到url后面的的方法,就是GET HEAD DELETE,与此对应的POST PUT方法将query拼到http body中。mutableHTTPRequestHeaders 储存http头部信息。mutableObservedChangedKeyPaths保存需要键值观察的值。
requestHeaderModificationQueue ??
2. 设置HTTP 头部字段
1 2 3 4 5 6 7
   |    NSMutableArray *acceptLanguagesComponents = [NSMutableArray array]; ... [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];     NSString *userAgent = nil; ... [self setValue:userAgent forHTTPHeaderField:@"User-Agent"];
   | 
 
分别设置了acceptLanguagesComponents和userAgent信息。
其中acceptLanguagesComponents 一般为:
userAgent为:
1
   | [工程名字]/[工程版本] (iPhone; iOS 10.2; Scale/2.00)
   | 
 
3.KVO
1 2 3 4 5
   | for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];        }    }
  | 
 
对一些属性进行 KVO,确保它们在改变后更新 NSMutableURLRequest 中对应的属性。其中AFHTTPRequestSerializerObservedKeyPaths为这些值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   | //是否允许使用设备的蜂窝移动网络来创建request,默认为允许 allowsCellularAccess,  /* 创建的request所使用的缓存策略,默认使用`NSURLRequestUseProtocolCachePolicy`,该策略表示   如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断  下一步操作,如: Cache-Control字段为must-revalidata, 则 询问服务端该数据是否有更新,无更新话  直接返回给用户缓存数据,若已更新,则请求服务端.*/ cachePolicy,  /**  如果设置HTTPShouldHandleCookies为YES,就处理存储在NSHTTPCookieStore中的cookies  HTTPShouldHandleCookies表示是否应该给request设置cookie并随request一起发送出去  */ HTTPShouldHandleCookies,  /**  HTTPShouldUsePipelining表示receiver(理解为iOS客户端)的下一个信息是否必须等到上一个请求回复才能发送。  如果为YES表示可以,NO表示必须等receiver收到先前的回复才能发送下个信息。  */ HTTPShouldUsePipelining,     /**      设定request的network service类型. 默认是`NSURLNetworkServiceTypeDefault`.      这个network service是为了告诉系统网络层这个request使用的目的      比如NSURLNetworkServiceTypeVoIP表示的就这个request是用来请求网际协议通话技术(Voice over IP)。
       系统能根据提供的信息来优化网络处理,从而优化电池寿命,网络性能等等      */ networkServiceType, /**  超时机制,默认60秒  */ timeoutInterval
   | 
 
AFURLRequestSerialization 协议的实现
初始化之后,如果调用了 - [AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:uploadProgress:downloadProgress:success:failure:],就会进入 AFHTTPRequestSerializer 的这一方法:
1 2 3 4
   | - (NSMutableURLRequest *)requestWithMethod:(NSString *)method                                  URLString:(NSString *)URLString                                 parameters:(id)parameters                                      error:(NSError *__autoreleasing *)error
   | 
 
其中调用了AFURLRequestSerialization 协议的实现:
1 2 3 4 5 6 7 8 9 10
   | - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request                                withParameters:(id)parameters                                         error:(NSError *__autoreleasing *)error{                                          1. 通过 HTTPRequestHeaders 字典设置头部字段 2. 将parameters转换为查询参数query 3. 将 query 添加到 URL 或者 HTTP body 中
  }
 
   | 
 
1.通过 HTTPRequestHeaders 字典设置头部字段
1 2 3 4 5
   | [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {      if (![request valueForHTTPHeaderField:field]) {          [mutableRequest setValue:value forHTTPHeaderField:field];      }  }];
  | 
 
2. 将parameters转换为查询参数query
1
   | query = AFQueryStringFromParameters(parameters);
   | 
 
AFQueryStringFromParameters (调用)-> AFQueryStringPairsFromDictionary -> AFQueryStringPairsFromKeyAndValue
其中AFQueryStringPairsFromKeyAndValue递归调用并解析,返回查询参数。
3. 将 query 添加到 URL 或者 HTTP body 中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {     if (query && query.length > 0) {         mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];     } } else {          if (!query) {         query = @"";     }     if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {         [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];     }     [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]]; }
 
  | 
 
最后这个方法会返回一个 NSMutableURLRequest。