AFNetworking到底长啥样(上)

发布时间:2020-06-06 19:11:30 作者:zlayne
来源:网络 阅读:267

AFNetworking是iOS界知名的网络三方库,现已完全取代了ASI。最新的AFNetworking3.0也早已从NSURLConnection切换到了NSURLSession,使用起来也更加方便。作为一名不断探索的资深iOSer,还是要看看源码提升下内功。

一、概述

首先看下AFNetworking的结构及其继承关系:

Class SuperClass Description
AFURLSessionManager NSObject ①用于管理NSURLSession实例。②负责生成dataTask、uploadTask和downloadTask。
AFHTTPSessionManager AFURLSessionManager AFURLSessionManager的子类,封装了网络请求并提供了Convenience Methods发起HTTP请求。
AFHTTPRequestSerializer NSObject 生成网络请求所需的Request,包括对参数的处理。
AFHTTPResponseSerializer NSObject 解析返回来的Response,并验证合法性。
AFSecurityPolicy NSObject 主要处理HTTPs通信。
AFURLSessionManagerTaskDelegate NSObject 作为task的delegate,调用回调。

涉及的主要类都在上表中了,下面简单说下其他的辅助类:

(1)_AFURLSessionTaskSwizzling:这个类只做一件事:使用Method Swizzling更改NSURLSessionDataTask及其父类的resumesuspend实现,在其调用时发送消息:AFNSURLSessionTaskDidResumeNotificationAFNSURLSessionTaskDidSuspendNotification即:

- (void)af_resume {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    [self af_resume];

    if (state != NSURLSessionTaskStateRunning) {
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
    }
}

- (void)af_suspend {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    [self af_suspend];

    if (state != NSURLSessionTaskStateSuspended) {
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
    }
}

(2)AFJSONRequestSerializer:是AFHTTPRequestSerializer的子类,相比于AFHTTPRequestSerializer,它增加了对parameters是否是合法JSON格式的校验。在POST情况下,parameters会通过NSJSONSerialization转化为NSData放到HTTPBody里。此外,header的Content-Type也会被设置为application/json

(3)AFQueryStringPair:包含fieldvalue属性,用于表示参数(eg. name='layne'),并且field和value要经过“PercentEscaped”处理,处理函数如下:

NSString * AFPercentEscapedStringFromString(NSString *string) {
    static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
    static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";

    NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
    [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];

    // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
    // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];

    static NSUInteger const batchSize = 50;

    NSUInteger index = 0;
    NSMutableString *escaped = @"".mutableCopy;

    while (index < string.length) {
        NSUInteger length = MIN(string.length - index, batchSize);
        NSRange range = NSMakeRange(index, length);

        // To avoid breaking up character sequences such as emoji
        range = [string rangeOfComposedCharacterSequencesForRange:range];

        NSString *substring = [string substringWithRange:range];
        NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
        [escaped appendString:encoded];

        index += range.length;
    }

    return escaped;
}

这里有两点需要说明:

①对于字符截断问题(eg.emoji),这里使用了:rangeOfComposedCharacterSequencesForRange:,根据给定的range调整实际的range来防止字符截断。

②这里设置了batchSize分块进行escape。为啥要这么做?FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028给出了具体解释:

Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead.

简单说就是,在8.1和8.2上超过100个中文字符会挂。

(4)AFStreamingMultipartFormData用于multipart方式上传的formData.

(5)AFHTTPBodyPart

(6)AFMultipartBodyStream

(7)AFJSONResponseSerializerAFHTTPResponseSerializer的子类,解析JSON格式的response.

(8)AFXMLParserResponseSerializerAFHTTPResponseSerializer的子类,解析(NSXMLParser)XML格式的response.

(9)AFXMLDocumentResponseSerializerAFHTTPResponseSerializer的子类,解析(NSXMLDocument)XML格式的response.

(10)AFPropertyListResponseSerializerAFHTTPResponseSerializer的子类,解析(NSXMLDocument)PropertyList格式的response,

(11)AFImageResponseSerializerAFHTTPResponseSerializer的子类,解析图片response。

(12)AFCompoundResponseSerializerAFHTTPResponseSerializer的子类,解析复合类型的response。

二、类分析

1.AFURLSessionManager

AFURLSessionManager是管理网络请求的主类,它的结构如下:

2.AFURLSessionManagerTaskDelegate

AFURLSessionManagerTaskDelegate这个类虽然后缀是·-Delegate,但它并不是一个协议,而是一个继承自NSObject的类。它和AFURLSessionManager都定义在文件AFURLSessionManager.m中。它的实例作为task的代理使用

注:AFURLSessionManagerTaskDelegate实例本身不持有task,它们之间的代理关系是以{<taskID:delegate>}的形式保存在可变字典mutableTaskDelegatesKeyedByTaskIdentifier中的。

3.AFHTTPSessionManager

AFHTTPSessionManagerAFURLSessionManager的子类,它针对HTTP请求封装了更为便利的方法。它的结构如下:

4.AFHTTPRequestSerializer

AFHTTPRequestSerializer继承自NSObject,用于封装request。

5.AFJSONRequestSerializer

AFJSONRequestSerializerAFHTTPRequestSerializer的子类,使用NSJSONSerialization将参数编码成JSON格式,并设置Content-Typeapplication/json。它重写了AFURLRequestSerialization协议方法:

- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                               withParameters:(id)parameters
                                        error:(NSError *__autoreleasing *)error
{
    NSParameterAssert(request);

    if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
        return [super requestBySerializingRequest:request withParameters:parameters error:error];
    }//若为GET/HEAD/DELETE方法,由于参数都拼接在URL中,因此无所谓json不json,直接调用父类的方法即可。

    NSMutableURLRequest *mutableRequest = [request mutableCopy];

    [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
        if (![request valueForHTTPHeaderField:field]) {
            [mutableRequest setValue:value forHTTPHeaderField:field];
        }
    }];//更新header数据

    if (parameters) {
        if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
            [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        }//设置Content-Type字段为“application/json”

        if (![NSJSONSerialization isValidJSONObject:parameters]) {
            if (error) {
                NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"The `parameters` argument is not valid JSON.", @"AFNetworking", nil)};
                *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
            }
            return nil;
        }//非法的json格式(NSDictionary)数据

        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error];//json序列化

        if (!jsonData) {
            return nil;
        }

        [mutableRequest setHTTPBody:jsonData];
    }

    return mutableRequest;
}

6.AFHTTPResponseSerializer

AFHTTPResonseSerializer继承自NSObject,实现了AFURLResponseSerialization协议:

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error;

在协议方法中根据acceptableStatusCodesacceptableContentTypes判断response合法性。

7.AFJSONResponseSerializer

AFJSONResponseSerializerAFHTTPResponseSerializer的子类。

以上就是AFNetworking主要的类结构及其功能。下一篇博客我们会以一个简单的POST请求来走一遍逻辑,看看AFN到底是如何工作的。

推荐阅读:
  1. AFNetworking到底长啥样(下)
  2. CRS和ASM有啥关系

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

afnetworking源码 afn post

上一篇:Liunx 部署邮件TLS/SSL加密通信服务

下一篇:mysql+pam模块实现vsftp虚拟用户统一管理

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》