AFNetworking3.0之前是对NSURLConnection的封装,2013年开发者大会随着ios7的发布,苹果开始大力推广NSURLSession,NSURLConnection也过期不再维护,AFN3.0之后也换做了NSURLSession作为核心请求方法。下面是他的结构图。
首先通过一个最常用的GET请求作为切入点,来了解一下AFN都替我们做了哪些事情。
请求流程:sesstion-url-request-task-resume
/**
* get请求
*/
+(void)GET_Path:(NSString *)path params:(NSDictionary *)params completed:(requestSuccessBlock)successBlock failed:(requestFailedBlock)failedBlock
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.requestSerializer.timeoutInterval = 5;
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html",nil];
[manager GET:path parameters:params progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
successBlock(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
failedBlock(error);
}];
}
1. 首先初始化一个AFHTTPSessionManager对象(session)
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
点进manager方法,可以看见它又调用了父类的初始化方法
+ (instancetype)manager {
return [[[self class] alloc] initWithBaseURL:nil];
}
- (instancetype)init {
return [self initWithBaseURL:nil];
}
- (instancetype)initWithBaseURL:(NSURL *)url {
return [self initWithBaseURL:url sessionConfiguration:nil];
}
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
return [self initWithBaseURL:nil sessionConfiguration:configuration];
}
/*
1.初始化
2.设置默认值
3.初始化最终都会走这个方法
*/
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
//调用父类初始化方法
self = [super initWithSessionConfiguration:configuration];
if (!self) {
return nil;
}
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
/*
为了确保NSURL +URLWithString:relativeToURL: works可以正确执行,在baseurlpath的最后添加‘/’
*/
//url有值且没有‘/’,那么在url的末尾添加‘/’
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
//给requestSerializer、responseSerializer设置默认值
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
进去父类初始化方法
/*
1.给self的属性设置值
2.给task添加delegate
*/
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
//设置默认的configuration
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
//持有configuration
self.sessionConfiguration = configuration;
//设置为delegate的操作队列并发的线程数量1
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
//默认为json解析
self.responseSerializer = [AFJSONResponseSerializer serializer];
//设置默认证书 无条件信任证书
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
//网络状态监听
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
//delegate= value taskid = key
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
//使用NSLock确保线程安全
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
//异步的获取当前session的所有未完成的task。其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有
//为了防止后台回来重新初始化这个session,一些之前的后台请求任务,导致程序的crash。https://github.com/AFNetworking/AFNetworking/issues/3499
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
return self;
}
可以看到它创建了一个配置类和一个串行队列作为参数创建了一个NSURLSession
类,并且初始化了序列化类AFJSONResponseSerializer
,网络安全策略类AFSecurityPolicy
,网络监听类AFNetworkReachabilityManager
,还把添加了task的代理,最终返回一个NSURLSession
的实例对象。
2.通过URL创建一个Request
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//返回一个task,然后开始网络请求
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
//开始网络请求
[dataTask resume];
return dataTask;
}
可以看到这里是返回一个task,再点进这个方法里,看是如何创建task的
/*
1.融合请求方式、url、参数生成一个request
2.把request传给父类,生成一个task
*/
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
NSError *serializationError = nil;
//relativeToURL表示将URLString拼接到baseURL后面
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
//xcode忽略编译器的警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//completionQueue不存在返回dispatch_get_main_queue
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
#pragma clang diagnostic pop
}
return nil;
}
//此时的request已经将参数拼接在url后面
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
这里一开始看到先用parameters,method,URLString创建了一个request请求,点进去
/*
1.初始化NSMutableURLRequest,并设置method
2.更新request上变化过的keypath
3.将参数编码添加到request,然后返回
*/
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
//断言如果nil,直接打印出来
NSParameterAssert(method);
NSParameterAssert(URLString);
//我们传进来的是一个字符串,在这里它帮你转成url
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
//设置请求方式(get、post、put。。。)
mutableRequest.HTTPMethod = method;
//将request的各种属性遍历
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
//给设置过得的属性,添加到request(如:timeout)
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
//通过kvc动态的给mutableRequest添加value
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
NSLog(@"request----%@",mutableRequest);
//将传入的参数进行编码,拼接到url后并返回
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
NSLog(@"request'''''''''%@",mutableRequest);
return mutableRequest;
}
3.创建task
上一步已经创建好了一个request,接下来就用request创建一个task,点进去看,
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
//原生的方法
dataTask = [self.session dataTaskWithRequest:request];
});
// 给任务添加代理
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
这里不仅创建了task,还给task添加了代理,以便监控他的上传和下载进度,还有返回值,点进去看看是如何绑定的。
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
// 根据task来创建delegate
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;
delegate.completionHandler = completionHandler;
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
//加锁确保中间代码块是原子操作
[self.lock lock];
//将delegate存入字典,以taskid作为key
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[delegate setupProgressForTask:task];
//给任务添加通知
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
这里可以看到并不是把AFURLSessionManager
直接设置成代理,而是单独创建了一个代理类AFURLSessionManagerTaskDelegate
来专门处理回调,这样大大降低了AFURLSessionManager
的耦合度和复杂度。
4.开始任务
最后在GET方法里,得到返回的task,并开始网络请求。
//开始网络请求
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//返回一个task,然后开始网络请求
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
//开始网络请求
[dataTask resume];
return dataTask;
}