AFNetworking简析之GET请求流程

AFNetworking3.0之前是对NSURLConnection的封装,2013年开发者大会随着ios7的发布,苹果开始大力推广NSURLSession,NSURLConnection也过期不再维护,AFN3.0之后也换做了NSURLSession作为核心请求方法。下面是他的结构图。


AFNetworking简析之GET请求流程_第1张图片
image.png

首先通过一个最常用的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;
}

你可能感兴趣的:(AFNetworking简析之GET请求流程)