框架结构 NSURLSession
1 2 3 AFURLSessionManager AFHTTPSessionManager (使用入口,父类是AFURLSessionManager)
Serialization
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 <AFURLRequestSerialization> AFHTTPRequestSerializer AFJSONRequestSerializer (父类是AFHTTPRequestSerializer) AFPropertyListRequestSerializer (父类是AFHTTPRequestSerializer) <AFURLResponseSerialization> AFHTTPResponseSerializer AFJSONResponseSerializer (父类是AFHTTPResponseSerializer) AFXMLParserResponseSerializer (父类是AFHTTPResponseSerializer) AFXMLDocumentResponseSerializer (macOS) (父类是AFHTTPResponseSerializer) AFPropertyListResponseSerializer (父类是AFHTTPResponseSerializer) AFImageResponseSerializer (父类是AFHTTPResponseSerializer) AFCompoundResponseSerializer (父类是AFHTTPResponseSerializer)
Additional Functionality
1 2 3 AFSecurityPolicy AFNetworkReachabilityManager
第一步 使用AFNetworking的第一步,就是创建AFHTTPSessionManager对象,方式如下:
1 AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
AFHTTPSessionManager继承自AFURLSessionManager。 这句代码完成了如下工作: 1,在AFURLSessionManager类中:
1 2 3 4 5 6 // 属性 1,sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; 2,operationQueue = [[NSOperationQueue alloc] init]; operationQueue.maxConcurrentOperationCount = 1; 3,session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:operationQueue]; 4,securityPolicy = [AFSecurityPolicy defaultPolicy];
2,在AFHTTPSessionManager类中:
1 2 3 // 属性 1,requestSerializer = [AFHTTPRequestSerializer serializer]; 2,responseSerializer = [AFJSONResponseSerializer serializer];
第二步 第二步调用POST方法 POST方法功能: 1.获取NSURLRequest实例。2.获取NSURLSessionDataTask实例。3.开启任务。 POST方法实现了网络请求的整个流程。
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 30 31 32 33 34 35 36 37 38 - (NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure { // 1.获取NSURLRequest实例 NSError *serializationError = nil; NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError]; if (serializationError) { if (failure) { dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ failure(nil, serializationError); }); } return nil; } // 2.获取NSURLSessionDataTask实例 __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { if (error) { if (failure) { failure(task, error); } } else { if (success) { success(task, responseObject); } } }]; // 3.开启任务 [task resume]; return task; }
NSURLRequest创建过程 创建NSURLRequest实例的过程,主要与 AFHTTPRequestSerializer、 AFStreamingMultipartFormData、 AFMultipartBodyStream、 AFHTTPBodyPart 类有关。
它们之间的关系如下如所示:
在AFHTTPRequestSerializer类中创建NSMutableURLRequest实例,代码如下:
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 30 31 32 33 34 35 36 37 38 39 40 41 42 - (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(NSDictionary *)parameters constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block error:(NSError *__autoreleasing *)error { NSParameterAssert(method); NSParameterAssert(![method isEqualToString:@"GET" ] && ![method isEqualToString:@"HEAD" ]); // 1 根据url创建一个NSMutableURLRequest实例,并且配置了HTTPMethod NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error]; // 2 创建AFStreamingMultipartFormData实例,并把NSMutableURLRequest实例作为属性。 __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding]; // 3 把请求参数(非文件数据)传递给AFStreamingMultipartFormData实例。 if (parameters) { for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { NSData *data = nil; if ([pair.value isKindOfClass:[NSData class]]) { data = pair.value; } else if ([pair.value isEqual:[NSNull null]]) { data = [NSData data]; } else { data = [[pair.value description] dataUsingEncoding:self.stringEncoding]; } if (data) { [formData appendPartWithFormData:data name:[pair.field description]]; } } } // 4 把请求参数(文件数据)传递给AFStreamingMultipartFormData实例。 if (block) { block(formData); } // 5 此步骤之前,拼接表单所需要的全部数据都保存在了AFStreamingMultipartFormData实例中。 // 给NSMutableURLRequest实例配置HTTPBodyStream和HTTPHeaderField return [formData requestByFinalizingMultipartFormData]; }
第1步的作用是,根据url创建一个NSMutableURLRequest实例,并且配置了HTTPMethod。 第2+3+4四步的作用是,把拼接表单所需要的全部数据都保存在AFStreamingMultipartFormData实例中,且把NSMutableURLRequest实例传递过去。 第5步的作用是,给NSMutableURLRequest实例配置HTTPBodyStream和HTTPHeaderField。
在AFStreamingMultipartFormData类中,拼接表单的数据都以AFHTTPBodyPart实例形式保存在属性bodyStream的HTTPBodyParts数组中。代码如下
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 // 1 - (void)appendPartWithFormData:(NSData *)data name:(NSString *)name { NSParameterAssert(name); NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"" , name] forKey:@"Content-Disposition" ]; [self appendPartWithHeaders:mutableHeaders body:data]; } // 2 - (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body { NSParameterAssert(body); AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; bodyPart.stringEncoding = self.stringEncoding; bodyPart.headers = headers; bodyPart.boundary = self.boundary; bodyPart.bodyContentLength = [body length]; bodyPart.body = body; // AFMultipartBodyStream [self.bodyStream appendHTTPBodyPart:bodyPart]; } // 3 - (NSMutableURLRequest *)requestByFinalizingMultipartFormData { if ([self.bodyStream isEmpty]) { return self.request; } // Reset the initial and final boundaries to ensure correct Content-Length [self.bodyStream setInitialAndFinalBoundaries]; [self.request setHTTPBodyStream:self.bodyStream]; [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@" , self.boundary] forHTTPHeaderField:@"Content-Type" ]; [self.request setValue:[NSString stringWithFormat:@"%llu" , [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length" ]; return self.request; }
根据方法1和2可知,表单数据保存在AFHTTPBodyPart实例中,AFHTTPBodyPart实例保存在属性bodyStream内部的数组中。 根据方法3可知,给NSMutableURLRequest实例设置HTTPBodyStream和HTTPHeaderField的值。
AFMultipartBodyStream是继承自NSInputStream类,重写内部方法read:maxLength:实现表单拼接。代码如下:
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 - (void)open { if (self.streamStatus == NSStreamStatusOpen) { return ; } self.streamStatus = NSStreamStatusOpen; [self setInitialAndFinalBoundaries]; // 把AFHTTPBodyPart数组,转换成枚举 self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator]; } - (NSInteger)read :(uint8_t *)buffer maxLength:(NSUInteger)length { if ([self streamStatus] == NSStreamStatusClosed) { return 0; } NSInteger totalNumberOfBytesRead = 0; while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { break ; } } else { NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead; // 调用AFHTTPBodyPart实例的read :maxLength:,拼接表单 NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read :&buffer[totalNumberOfBytesRead] maxLength:maxLength]; if (numberOfBytesRead == -1) { self.streamError = self.currentHTTPBodyPart.inputStream.streamError; break ; } else { totalNumberOfBytesRead += numberOfBytesRead; if (self.delay > 0.0f) { [NSThread sleepForTimeInterval:self.delay]; } } } } return totalNumberOfBytesRead; }
由代码可知,AFMultipartBodyStream中的read:maxLength:方法并不是真正做表单拼接的地方,真正的地方在AFHTTPBodyPart实例的read:maxLength:方法中。
在AFHTTPBodyPart类中,实现了真正的表单拼接。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 // 1 - (NSInteger)read :(uint8_t *)buffer maxLength:(NSUInteger)length { NSInteger totalNumberOfBytesRead = 0; if (_phase == AFEncapsulationBoundaryPhase) { NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; } if (_phase == AFHeaderPhase) { NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; } if (_phase == AFBodyPhase) { NSInteger numberOfBytesRead = 0; numberOfBytesRead = [self.inputStream read :&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; if (numberOfBytesRead == -1) { return -1; } else { totalNumberOfBytesRead += numberOfBytesRead; if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) { [self transitionToNextPhase]; } } } if (_phase == AFFinalBoundaryPhase) { NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; } return totalNumberOfBytesRead; } // 2 - (NSInteger)readData:(NSData *)data intoBuffer:(uint8_t *)buffer maxLength:(NSUInteger)length { NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length)); [data getBytes:buffer range:range]; _phaseReadOffset += range.length; if (((NSUInteger)_phaseReadOffset) >= [data length]) { [self transitionToNextPhase]; } return (NSInteger)range.length; }
核心代码是方法2中的[data getBytes:buffer range:range];
NSURLSessionDataTask创建过程 创建NSURLSessionDataTask实例的过程,主要与 AFURLSessionManager 类有关。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler { __block NSURLSessionUploadTask *uploadTask = nil; url_session_manager_create_task_safely(^{ // self.session在初始化方法中已经创建好了。 uploadTask = [self.session uploadTaskWithStreamedRequest:request]; }); [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; return uploadTask; }