您的位置:首页 > 产品设计 > UI/UE

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

2016-03-02 17:35 519 查看
为了迎合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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: