zoukankan      html  css  js  c++  java
  • AFNetworking基本模块

    AFNetworking主要分为5个模块

    • 通信模块(AFURLSessionManager, AFHTTPSessionManager)
    • 网络状态监听
    • 安全模块
    • 通信序列化/反序列化模块
    • UIKit相关

    实际上AFNetworking是对原生的NSURLSession进行的封装,上面所说的四个部分并不是并列的关系,所有请求逻辑全部交由AFURLSessionManager来处理,其他的网络监听,安全和序列化/反序列化全是为AFURLSessionManager服务或者说是以其为基础的。至于AFHTTPSessionManager本身也是继承自URLSessionManager的一层封装,本身并不干活,只是将请求逻辑分发给其父类去做。

    如上所说,用户对接的其实是AFHTTPSessionManager类,当需要实例化网络请求的时候,一般使用下面的方法

    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
    + (instancetype)manager;
    - (instancetype)initWithBaseURL:(nullable NSURL *)url;
    - (instancetype)initWithBaseURL:(nullable NSURL *)url
    sessionConfiguration:(nullable NSURLSessionConfiguration
    *)configuration;
    其中
    - (instancetype)initWithBaseURL:(NSURL *)url
    sessionConfiguration:(NSURLSessionConfiguration *)configuration
    {
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
    return nil;
    }
    // 对传进来的url进行判断,判断结束是否有“/”
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
    url = [url URLByAppendingPathComponent:@""];
    }
    self.baseURL = url;
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    return self;
    }

    而其实这个初始化的调用,也是先调用了父类AFURLSessionManager的初始化方法,这个后面再说。

    在AFHTTPSessionManager中,基本是

    1
    2
    3
    4
    - (NSURLSessionDataTask *)GET:(NSString *)URLString
    parameters:(id)parameters
    success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
    failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure

    这样的方法,将GET,POST,PUT,DELETE等指令全部包装起来,交给AFURLSessionManager来完成。一般都很简单地只是将请求交给父类,获取对应的NSURLSessionTask然后调用其resume方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    - (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
    {
    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
    URLString:URLString
    parameters:parameters
    uploadProgress:nil
    downloadProgress:downloadProgress
    success:success
    failure:failure];
    // 正式开始网络请求
    [dataTask resume];
    return dataTask;
    }

    比如这个GET方法的包装,就是这样一个流程。
    AFHTTPSessionManager还有另一个功能就是把调用者发起得请求转换编码成最后需要的request,然后再由父类进行真正的网络请求

    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
    - (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;
    // 将需要的部件放到一起组成一个request
    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;
    }
    __block NSURLSessionDataTask *dataTask = nil;
    // 若成功则用这个request生成一个dataTask实例交给回调方法
    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);
    }
    }
    }];
    }

    如上面的代码就是调用转化编码的请求,如果没有报错,那么后续就会对这个request作为参数来发起网络请求。

    序列/反序列RequestSerialization

    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
    - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
    URLString:(NSString *)URLString
    parameters:(id)parameters
    error:(NSError *__autoreleasing *)error
    {
    NSParameterAssert(method);
    NSParameterAssert(URLString);
    NSURL *url = [NSURL URLWithString:URLString];
    NSParameterAssert(url);
    // 通过url来创建一个request实例
    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    // 将HTTP请求类型作为参数赋给request
    mutableRequest.HTTPMethod = method;
    // 循环参数列表
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
    if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
    [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
    }
    }
    // 将parameters编码之后交给request
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
    return mutableRequest;
    }

    上面就是初始化一个request的对应方法,值得一说的是,将parameter进行编码的部分,本质是将本来包含了各种dictionary以及array的完整dictionary中的所有参数全部“拉伸”开来变成一个字符串,然后根据网络请求的类型来决定是将这个字符串参数放到URL后面还是直接封装到HTTP请求体body中。
    补充一下其中具体的细节:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
    static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    _AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
    });
    return _AFHTTPRequestSerializerObservedKeyPaths;
    } // 这是一个C的函数,本质就是封装了一些属性的名字

    mutableObservedChangedKeyPaths是类的一个属性,负责将RequestSerializer类和NSURLRequest的相关属性进行KVO监听:

    具体的实现机制就是在init时初始化一个mutableObservedChangedKeyPaths空的set,并且为AFHTTPRequestSerializerObservedKeyPaths()中所有属性同名的set方法添加oberser。然后每当set方法被调用的时候就添加到mutableObservedChangedKeyPaths中,这样其实我们很容易看出来循环参数列表的作用:就是将可能调用的request属性中确实调用了的部分给取出来作为一个数组。

    具体编码方法

    然后所有元素都有了,剩下来的就是具体的编码方法了:

    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
    56
    57
    - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
    withParameters:(id)parameters
    error:(NSError *__autoreleasing *)error
    {
    NSParameterAssert(request);
    NSMutableURLRequest *mutableRequest = [request mutableCopy];
    // 补全request对象,使用httpheader这个参数
    [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
    if (![request valueForHTTPHeaderField:field]) {
    [mutableRequest setValue:value forHTTPHeaderField:field];
    }
    }];
    // 对参数parameter进行编码
    NSString *query = nil;
    if (parameters) {
    // 如果存在自定义的解析方法就直接调用
    if (self.queryStringSerialization) {
    NSError *serializationError;
    query = self.queryStringSerialization(request, parameters, &serializationError);
    if (serializationError) {
    if (error) {
    *error = serializationError;
    }
    return nil;
    }
    } else { // 否则使用默认的方法
    switch (self.queryStringSerializationStyle) {
    case AFHTTPRequestQueryStringDefaultStyle:
    query = AFQueryStringFromParameters(parameters);
    break;
    }
    }
    }
    // 将编码完成的参数和URL合并起来,或者作为HTTP的body。判断该request中是否包含了GET、HEAD、DELETE(都包含在HTTPMethodsEncodingParametersInURI)。因为这几个method的quey是拼接到url后面的。而POST、PUT是把query拼接到http body中的
    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 {
    // #2864: an empty string is a valid x-www-form-urlencoded payload
    if (!query) {
    query = @"";
    }
    if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
    [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    }
    [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
    }
    return mutableRequest;
    }

    上面可以看到,对一个request进行编码的流程首先是根据已有的HTTPRequestHeaders这个参数来对request的参数进行补全,HTTPRequestHeaders是一个dictionary,首先遍历这个dictionary,如果request这个URLRequest对象不包含某个key,那么就添加一个对应的键值对给它。
    然后是最重要的,query的编码部分,顺着query = AFQueryStringFromParameters(parameters) 这个部分找下去可以找到最终的编码规则:

    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
    NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
    NSMutableArray *mutablePairs = [NSMutableArray array];
    for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
    [mutablePairs addObject:[pair URLEncodedStringValue]];
    }
    return [mutablePairs componentsJoinedByString:@"&"];
    }
    NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
    return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
    }
    NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
    NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
    if ([value isKindOfClass:[NSDictionary class]]) {
    NSDictionary *dictionary = value;
    // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
    for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
    id nestedValue = dictionary[nestedKey];
    if (nestedValue) {
    [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
    }
    大专栏  AFNetworking基本模块line"> }
    } else if ([value isKindOfClass:[NSArray class]]) {
    NSArray *array = value;
    for (id nestedValue in array) {
    [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
    }
    } else if ([value isKindOfClass:[NSSet class]]) {
    NSSet *set = value;
    for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
    [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
    }
    } else {
    [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
    }
    return mutableQueryStringComponents;
    }

    先将parameter整个dictionary进行处理,上面最后一个方法是一个递归调用,如果参数是dictionary,那么对其中每一个元素进行拆分,得到一个dic[key]=value这样的对,并保存在一个临时数组中;如果参数是数组,那么拆分后得到array[]= value这样的对,也保存在临时数组中…这样将parameter中所有最小元素全部拆分成为键值对保存在一个最终的数组中之后,便利数组,每个对间隔插入“&”,最后成为一个字符串,就是最终网络请求使用的query。

    具体变化如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @{
    @"name" : @"heqian",
    @"phone": @{@"mobile": @"123", @"home": @456},
    @"game": @[@"dark souls", @"tales of zelda"],
    @"nums": [NSSet setWithObjects:@"1", @"2", nil]
    }
    最终会变化为
    name=heqian&phone[mobile]=123&phone[home]=456&game[]=dark souls&game[]=tales of zelda
    &nums=1&num=2

    完成query的编码之后,根据请求的种类,来判断是直接拼接在URL之后,还是应该放在HTTP请求的body中。

    AFURLSessionManager核心解析

    初始化方法:

    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
    - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
    return nil;
    }
    if (!configuration) {
    configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }
    self.sessionConfiguration = configuration;
    // queue并发线程设置为1
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;
    // 设置delegate,等于是包装了一次NSURLSession,它所需要的代理全部交给AFURLSessionManager来处理
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
    // 响应转码
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    // 安全策略
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];
    #if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
    #endif
    // 设置存储NSURL task与AFURLSessionManagerTaskDelegate的词典,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    // 加锁,防止线程冲突
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;
    // 将task关联的代理全部置为空
    [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;
    }

    基本是很普通的对参数的初始化,值得说明的是(1)self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init] 这个dictionary,在AFNetworking中每一个task都会匹配一个taskDelegate来做task的事件处理,上面的处理中在创建了dictionary之后还创建了对应的NSLock,理所当然是为了保证多线程的情况下操作dictionary不会发生错误 (2)为什么要清空session中的所有task,我们知道在初始化的时候session中应该不会有任何task才对。但是实际上后台也在运行一个session,当任务从后台的session返回的时候,是可以重新恢复到session中的,只要对应的ID相同。所以有这么一种可能,创建了新的session之后,后台session返回了刚刚处理完的task,然后无意中填充到这个新的session中,这样的情况下,我们就必须清空所有task。

    之前在序列化中提到有一系列方法能返回task:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    - (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;
    // 这里因为IOS8以下存在一个BUG,在并发队列中创建task可能导致不正确的completionHandlers回调,[#2093]( https://github.com/AFNetworking/AFNetworking/issues/2093 “#2093”),这里直接做了串行处理,保证每个task的completionHandler都是正确的
    url_session_manager_create_task_safely(^{
    dataTask = [self.session dataTaskWithRequest:request];
    });
    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
    return dataTask;
    }

    基本上这类的方法都是两个步骤:(1)调用session方法,通过request参数来生成task,上面的串行处理url_session_manager_create_task_safely只是一个判断系统是否会出现BUG的一个包装而已,如果是IOS8以上(包括8),不存在这个BUG那么就可以直接执行。
    (2)给每个task对象创建一个对应的delegate,实际上这个delegate系统是整个类中最核心的部分

    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
    - (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
    {
    // 为dataTask生成一个对应的taskDelegate,并且由AFURLSessionManager自己来管理
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;
    // 关键元素taskDescriptionForSessionTasks用来发送开始和挂起通知时用到,这就是task和manager的关联纽带
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    // 将delegate对象与dataTask建立关系
    [self setDelegate:delegate forTask:dataTask];
    // 设置delegate的两个进度block
    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
    }
    - (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
    forTask:(NSURLSessionTask *)task
    {
    NSParameterAssert(task);
    NSParameterAssert(delegate);
    // 加锁保证线程安全
    [self.lock lock];
    // dictionary以taskIdentifier作为key,将delegate放入其中
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    // 添加task到nofification中,监听其动态
    [self addNotificationObserverForTask:task];
    // 解锁
    [self.lock unlock];
    }

    以上就主要作用是把task和其代理建立起关联,并且保存在manager的字典中,
    到这里准备工作就做好了,之前在AFHTTPSessionManager中我们看到,返回一个task之后,直接调用了resume方法,其实就是开启了任务
    而在初始化方法中

    1
    2
    3
    self.session = [NSURLSession
    sessionWithConfiguration:self.sessionConfiguration delegate:self
    delegateQueue:self.operationQueue];

    其实是把AFURLSessionManager作为了所有task的delegate。

    我们可以看到AFURLSessionManager自己完成了4个delegate的实现

    1
    2
    3
    4
    NSURLSessionDelegate
    NSURLSessionTaskDelegate
    NSURLSessionDataDelegate
    NSURLSessionDownloadDelegate

    这样就将复杂的NSURLSession的各种delegate做了一个综合的处理,最后通过AFURLSessionManager转发到自定义delegate的方法就变得非常清晰了,只有比如

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    - (void)URLSession:(NSURLSession *)session
    task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error
    {
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    // delegate may be nil when completing a task in the background
    if (delegate) {
    [delegate URLSession:session task:task didCompleteWithError:error];
    [self removeDelegateForTask:task];
    }
    if (self.taskDidComplete) {
    self.taskDidComplete(session, task, error);
    }
    }


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    - (void)URLSession:(NSURLSession *)session
    dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
    {
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    [delegate URLSession:session dataTask:dataTask didReceiveData:data];
    if (self.dataTaskDidReceiveData) {
    self.dataTaskDidReceiveData(session, dataTask, data);
    }
    }

    这样的方法中会需要将消息转发出去让自定义的delegate来完成。值得一提的是,这些protocol并不是并列的关系
    在NSURLSession的声明文件中我们可以看到,NSURLSessionDelegate 继承自NSObject,而NSURLSessionTaskDelegate继承自NSURLSessionDelegate,另外三个protocol则全部继承自NSURLSessionTaskDelegate。那么当一个delegate需要执行操作的时候,它会通过这个继承的顺序依次查找protocol的实现,另外AFNetworking重写了respondsToSelector:(SEL)selector这个方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    - (BOOL)respondsToSelector:(SEL)selector {
    if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) {
    return self.taskWillPerformHTTPRedirection != nil;
    } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) {
    return self.dataTaskDidReceiveResponse != nil;
    } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) {
    return self.dataTaskWillCacheResponse != nil;
    } else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) {
    return self.didFinishEventsForBackgroundURLSession != nil;
    }
    return [[self class] instancesRespondToSelector:selector];
    }

    上面的self.taskWillPerformHTTPRedirection,self.dataTaskDidReceiveResponse等全是自定义的回调block,如果没有对block进行赋值,那么方法回调也没有什么意义。
    在AFURLSessionManager中声明了许多这样的block

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid;
    @property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge;
    @property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession;
    @property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection;
    @property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge;
    @property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream;
    @property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData;
    @property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete;
    @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse;
    @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask;
    @property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData;
    @property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse;
    @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
    @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData;
    @property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume;

    它们通过set方法进行赋值(这样的好处在于,使用者可以通过set方法的接口来了解对应block需要的参数)

    AFNetworking好处

    由于苹果推出的NSURLSession帮助我们完成了任务的调度功能,所以AFNetworking3.0不像2.0的时候一样有了那么多的底层功能,但是实际上它还是完成了很多能节省开发者大量时间的任务。比如request拼接,请求的格式转换,各种delegate的封装,并且在完成任务之后的回调上进行了很多判断。如果这些工作全部交给开发者自己在NSURLSession的基础上完成,那么毫无疑问工作量会大大增加。

  • 相关阅读:
    HDOJ2032_杨辉三角
    素数问题练习_HDOJ1262
    素数问题三步曲_HDOJ2098
    小黄衫的故事
    软件工程实践总结
    Beta吐槽
    Beta版本讨论
    Beta版本总结
    Beat版本冲刺(七)
    Beta版本冲刺(六)
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12041317.html
Copyright © 2011-2022 走看看