iOS学习----------AFNetworking(2)request创建和请求参数的序列化

为了迎合iOS新版本的升级, AFNetworking在3.0版本中删除了基于 NSURLConnection API的所有支持。如果你的项目以前使用过这些API,建议您立即升级到基于 NSURLSession 的API的AFNetworking的版本。迁移方法:AFNetworking 3.0迁移指南
AFNetworking源码大致分为以下几个部分:
网络监控:AFNetworkReachabilityManager
网络安全策略:AFSecurityPolicy
请求数据序列化:AFURLRequestSerialization
响应数据序列化:AFURLResponseSerialization
网络请求管理:AFURLSessionManager(AFHTTPSessionManager继承于AFURLSessionManager)
本部分主要介绍请求数据序列化同时包含request的创建(AFURLRequestSerialization)

AFURLRequestSerialization.h文件
协议:AFURLRequestSerialization
协议方法:

- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                               withParameters:(nullable id)parameters
                                        error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;

协议:AFMultipartFormData
方法:

- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
                         name:(NSString *)name
                        error:(NSError * _Nullable __autoreleasing *)error;

- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
                         name:(NSString *)name
                     fileName:(NSString *)fileName
                     mimeType:(NSString *)mimeType

- (void)appendPartWithInputStream:(nullable NSInputStream *)inputStream
                             name:(NSString *)name
                         fileName:(NSString *)fileName
                           length:(int64_t)length
                         mimeType:(NSString *)mimeType;

- (void)appendPartWithFileData:(NSData *)data
                          name:(NSString *)name
                      fileName:(NSString *)fileName
                      mimeType:(NSString *)mimeType;

- (void)appendPartWithFormData:(NSData *)data
                          name:(NSString *)name;

- (void)appendPartWithHeaders:(nullable NSDictionary <NSString *, NSString *> *)headers body:(NSData *)body;

- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes delay:(NSTimeInterval)delay;

类:AFHTTPRequestSerializer、AFPropertyListRequestSerializer

AFURLRequestSerialization.m文件
创建NSMutableURLRequest对象,从第一个方法入手

/**
 使用指定的HTTP method和URLString来构建一个NSMutableURLRequest对象实例

 如果method是GET、HEAD、DELETE,那parameter将会被用来构建一个基于url编码的查询字符串(query url)
 ,并且这个字符串会直接加到request的url后面。对于其他的Method,比如POST/PUT,它们会根
 据parameterEncoding属性进行编码,而后加到request的http body上。
 @param method request的HTTP methodt,比如 `GET`, `POST`, `PUT`, or `DELETE`. 该参数不能为空
 @param URLString 用来创建request的URL
 @param parameters 既可以对method为GET的request设置一个查询字符串(query string),也可以设置到request的HTTP body上
 @param error 构建request时发生的错误

 @return  一个NSMutableURLRequest的对象
 */
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString  parameters:(id)parameters error:(NSError *__autoreleasing *)error
{
    //断言
    //方法或函数应当在代码最开始处使用 NSParameterAssert / NSCParameterAssert 来强制输入的值满足先验条件,这是一条金科玉律;其他情况下使用 NSAssert / NSCAssert。
    NSParameterAssert(method);
    NSParameterAssert(URLString);
    NSURL *url = [NSURL URLWithString:URLString];
    NSParameterAssert(url);

    //创建mutableRequest病指定请求方法
    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    mutableRequest.HTTPMethod = method;

    //通过循环将本类中的几个keypath设置在mutableRequest中
    //AFHTTPRequestSerializerObservedKeyPaths()方法为初始化各个key path
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
        //使用kvc的方式设置mutableRequest的属性
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }

    //设置request的http header field  和序列化参数
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

    return mutableRequest;
}

AFHTTPRequestSerializerObservedKeyPaths()方法,将本类中的key path(就是属性名)搜集在一起


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;
}

这几种keypath的意思如下:
allowsCellularAccess: 是否允许使用设备的蜂窝移动网络来创建request,默认为允许
cachePolicy: 创建的request所使用的缓存策略,默认使用NSURLRequestUseProtocolCachePolicy,该策略表示,如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断,下一步操作,如: Cache-Control字段为must-revalidata, 则 询问服务端该数据是否有更新,无更新话直接返回给用户缓存数据,若已更新,则请求服务端.
HTTPShouldHandleCookies:
如果设置HTTPShouldHandleCookies为YES,就处理存储在NSHTTPCookieStore中的cookies
HTTPShouldHandleCookies表示是否应该给request设置cookie并随request一起发送出去
HTTPShouldUsePipelining:HTTPShouldUsePipelining表示receiver(理解为iOS客户端)的下一个信息是否必须等到上一个请求回复才能发送。
如果为YES表示可以,NO表示必须等receiver收到先前的回复才能发送下个信息。
networkServiceType: 设定request的network service类型. 默认是NSURLNetworkServiceTypeDefault.
这个network service是为了告诉系统网络层这个request使用的目的 比如NSURLNetworkServiceTypeVoIP表示的就这个request是用来请求网际协议通话技术(Voice over IP)。
系统能根据提供的信息来优化网络处理,从而优化电池寿命,网络性能等等
timeoutInterval:超时时间 60秒

第二部分代码--设置request的header field 和序列化参数(get 、head 、delete这三种方法创建request)

- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error
{
    //request不能为空
    NSParameterAssert(request);
    NSMutableURLRequest *mutableRequest = [request mutableCopy];

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

    NSString *query = nil;
    if (parameters) {
            //自定义序列化的block,如果用户实现了这个方法就调用这个block
        if (self.queryStringSerialization) {
            NSError *serializationError;
            query = self.queryStringSerialization(request, parameters, &serializationError);

            if (serializationError) {
                if (error) {
                    *error = serializationError;
                }

                return nil;
            }
        } else {
              //使用afn内部的序列化方法
            switch (self.queryStringSerializationStyle) {
                case AFHTTPRequestQueryStringDefaultStyle:
                    query = AFQueryStringFromParameters(parameters);
                    break;
            }
        }
    }

    //将序列化后的参数与url进行拼接
    //HTTPMethodsEncodingParametersInURI:GET, HEAD, DELETE
    if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
     /*mutableRequest.URL.query ? @"&%@" : @"?%@", query判断后面是否有参数,如果有参数 用&号拼接 如果没有参数使用?拼接 */
        if (query) {
          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;
}

AFN内部的序列化方法


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) {
            // 递归解析数据,baz[]=1&baz[]=2&baz[]=3&foo=bar
                  [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
            }
        }
    } 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值