前言
學(xué)習(xí)一下大神的編碼思想是很有必要的,另外用了怎么久的開源庫不認(rèn)真對(duì)待有點(diǎn)說不過去箍邮。這里借助部分博客以及源碼來學(xué)習(xí)恋博。如有不足,多多指點(diǎn)涨冀!
目錄
- AFNetworking架構(gòu)及主要模塊的功能
- AFNetworking具體模塊的探究
AFNetworking架構(gòu)及主要模塊的功能
AFNetworking的導(dǎo)入這里就不多介紹填硕,直接放目錄
可以清楚的看到AFNetworking大致分為以下幾個(gè)模塊
- 網(wǎng)絡(luò)通信模塊
- AFHTTPSessionManager
- AFURLSessionManager
- 網(wǎng)絡(luò)狀態(tài)監(jiān)聽模塊
- AFNetworkReachabilityManager
- 網(wǎng)絡(luò)通信安全策略模塊(有關(guān)https的部分)
- AFSecurityPolicy
- 網(wǎng)絡(luò)通信信息序列化/反序列化模塊
- AFURLRequestSerialization
- AFURLResponseSerialization
- 對(duì)于iOS UIKit庫的擴(kuò)展(UIKit)
- UIKit
UIKit與其他的沒有直接關(guān)系。除去后
其中AFHTTPSessionManager是繼承于AFURLSessionManager的鹿鳖,我們一般做網(wǎng)絡(luò)請(qǐng)求都是用這個(gè)類扁眯,但是它本身是沒有做實(shí)事的,只是做了一些簡(jiǎn)單的封裝翅帜,把請(qǐng)求邏輯分發(fā)給父類AFURLSessionManager或者其它類去做姻檀。
首先寫一個(gè)GET請(qǐng)求:
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]init];
[manager GET:@"http://localhost" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
首先我們用初始化方法生成一個(gè)manager,我們點(diǎn)進(jìn)去看下初始化做了什么:
- (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];
}
- (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
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
- 初始化都調(diào)用了
- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration
- 其實(shí)初始化方法都調(diào)用了父類的初始化方法涝滴,父類也就是AF3.x最最重要的AFURLSessionManager绣版。幾乎所有的類都是圍繞著這個(gè)類在處理業(yè)務(wù)邏輯。
- 除此之外歼疮,方法中把baseURL存了起來杂抽,還生成了一個(gè)請(qǐng)求序列對(duì)象和一個(gè)響應(yīng)序列對(duì)象。后面再細(xì)說這兩個(gè)類是干嘛的韩脏。
直接來到父類AFURLSessionManager的初始化方法:
- (instancetype)init {
return [self initWithSessionConfiguration:nil];
}
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
//初始化session缩麸,設(shè)置代理
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
//響應(yīng)轉(zhuǎn)碼
self.responseSerializer = [AFJSONResponseSerializer serializer];
//設(shè)置默認(rèn)安全策略
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
// 設(shè)置存儲(chǔ)NSURL task與AFURLSessionManagerTaskDelegate的詞典(重點(diǎn),在AFNet中骤素,每一個(gè)task都會(huì)被匹配一個(gè)AFURLSessionManagerTaskDelegate 來做task的delegate事件處理
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
//設(shè)置AFURLSessionManagerTaskDelegate 詞典的??匙睹,確保詞典在多線程訪問的線程安全
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
//置空task關(guān)聯(lián)的代理
[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;
}
- 這個(gè)就是最終的初始化方法了,注釋應(yīng)該寫的很清楚济竹,唯一需要說的就是三點(diǎn):
-
self.operationQueue.maxConcurrentOperationCount = 1;
這個(gè)operationQueue就是我們代理回調(diào)的queue痕檬。這里把代理回調(diào)的線程并發(fā)數(shù)設(shè)置為1了。 - 第二就是我們初始化了一些屬性送浊,其中包括
self.mutableTaskDelegatesKeyedByTaskIdentifier
梦谜,這個(gè)是用來讓每一個(gè)請(qǐng)求task和我們自定義的AF自定義代理來建立映射用的,其實(shí)對(duì)task的代理運(yùn)行了一個(gè)封裝,并且轉(zhuǎn)發(fā)代理到AF代理來建立映射用唁桩,其實(shí)AF對(duì)task的代理進(jìn)行了一個(gè)封裝闭树,并且轉(zhuǎn)發(fā)代理到AF自定義的代理,這是AF比較重要的一部分荒澡,接下來我們會(huì)具體講這一塊报辱。 - 第三就是下面這個(gè)方法:
-
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
}];
首先說說這個(gè)方法是干什么的:這個(gè)方法用來異步的獲取當(dāng)前session的所有未完成task。其實(shí)講道理來說在初始化中調(diào)用這個(gè)方法應(yīng)該里面一個(gè)task都不會(huì)有单山。我們打斷點(diǎn) 去看看碍现,也確實(shí)如此,里面的數(shù)組都是空的米奸。
- **原來這是無力從后臺(tái)回來昼接,重新初始化session,防止一些之前的后臺(tái)請(qǐng)求任務(wù)悴晰,導(dǎo)致程序crash慢睡。
初始化方法到這里就完成了。
接下來我們看看網(wǎng)絡(luò)請(qǐng)求:
- (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;
}
方法走到類AFHTTPSessionManager中來铡溪,調(diào)用父類漂辐,也就是我們整個(gè)AF3.x的核心類AFURLSessionManager的方法,生成了一個(gè)系統(tǒng)的NSURLSessionDataTask實(shí)例棕硫,并且開始網(wǎng)絡(luò)請(qǐng)求者吁。
我們繼續(xù)往父類里看,看看這個(gè)方法到底做了什么:
- (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;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
#pragma clang diagnostic pop
}
return nil;
}
__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;
}
- 這個(gè)方法做了兩件事:
1饲帅、用self.requestSerializer和各種參數(shù)去獲取了一個(gè)我們最終網(wǎng)絡(luò)需要的NSMutableURLRequest實(shí)例复凳。
2、調(diào)用另外一個(gè)dataTaskWithRequest去拿到我們最終需要的NSURLSessionDataTask實(shí)例灶泵,并且在完成的回調(diào)里育八,調(diào)用我們傳過來的成功和失敗的回調(diào)。 - 注意下面這個(gè)方法赦邻,我們常用來push pop 搭配髓棋,來忽略一些編譯器的警告:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
#pragma clang diagnostic pop
這里是用來忽略:?帶來的警告惶洲,具體的各種編輯器警告描述按声,可以參考這篇:各種編譯器的警告
- 說到底這個(gè)方法還是沒有做實(shí)事,我們繼續(xù)到requestSerializer方法里去看恬吕,看看AF到底如何拼接我們需要的request的:
接著我們跑到AFURLRequestSerialization類中:
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
//斷言签则,debug模式下,如果缺少改參數(shù)铐料,crash
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
//將request的各種屬性循環(huán)遍歷
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
//如果自己觀察到的發(fā)生變化的屬性渐裂,在這些方法里
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
//把給自己設(shè)置的屬性給request設(shè)置
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
//將傳入的parameters進(jìn)行編碼豺旬,并添加到request中
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
- 講一下這個(gè)方法,這個(gè)方法做了3件事:
1)設(shè)置request的請(qǐng)求類型柒凉,get族阅,post,put膝捞、坦刀、、等
2)往request里添加一些參數(shù)設(shè)置蔬咬,其中AFHTTPRequestSerializerObservedKeyPaths()是個(gè)C函數(shù)求泰,返回一個(gè)數(shù)組,我們來看看這個(gè)函數(shù):
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
static dispatch_once_t onceToken;
// 此處需要observer的keypath為allowsCellularAccess计盒、cachePolicy、HTTPShouldHandleCookies
// HTTPShouldUsePipelining芽丹、networkServiceType北启、timeoutInterval
dispatch_once(&onceToken, ^{
_AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
});
//就是一個(gè)數(shù)組里裝了很多方法的名字,
return _AFHTTPRequestSerializerObservedKeyPaths;
}
其實(shí)這個(gè)函數(shù)就是封裝了一些屬性的名字,這些都是NSUrlRequest的屬性拔第。
再來看看self.mutableObservedChangedKeyPaths咕村,這個(gè)是當(dāng)前類的一個(gè)屬性:
@property (readwrite, nonatomic, strong) NSMutableSet *mutableObservedChangedKeyPaths;
在-init方法對(duì)這個(gè)集合進(jìn)行了初始化,并且對(duì)當(dāng)前類的和NSUrlRequest相關(guān)的那寫屬性添加了KVO監(jiān)聽:
//每次都會(huì)重置變化:
self.mutableObservedChangedKeyPaths = [NSMutableSet set];
//給這些方法添加觀察者為自己蚊俺,就是request的各種屬性懈涛,set方法
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
}
}
KVO觸發(fā)的方法:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(__unused id)object
change:(NSDictionary *)change
context:(void *)context
{
//當(dāng)觀察到這些set方法被調(diào)用了,而且不為null就會(huì)添加到集合中泳猬,否則移除
if (context == AFHTTPRequestSerializerObserverContext) {
if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
[self.mutableObservedChangedKeyPaths removeObject:keyPath];
} else {
[self.mutableObservedChangedKeyPaths addObject:keyPath];
}
}
}
至此我們知道self.mutableObservedChangedKeyPaths
其實(shí)就是我們自己設(shè)置的request屬性值的集合批钠。
接下來調(diào)用:
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
用KVC的方式,把屬性值都設(shè)置到我們請(qǐng)求的request中去得封。
3)把需要傳遞的參數(shù)進(jìn)行編碼埋心,并且設(shè)置到request中去:
//將傳入的parameters進(jìn)行編碼,并添加到request中
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
#pragma mark - AFURLRequestSerialization
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
//到自己的header中遍歷忙上,如果有值則設(shè)置給request的header
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
//來把各種類型的參數(shù)拷呆,array,dic疫粥,set轉(zhuǎn)化成字符串茬斧,給request
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 {
//AF默認(rèn)解析方式
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters);
break;
}
}
}
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;
}
這個(gè)方法做了3件事:
1、從 self.HTTPRequestHeaders
中拿到設(shè)置的參數(shù)梗逮,賦值要請(qǐng)求的request里去
2铡原、把請(qǐng)求網(wǎng)絡(luò)的參數(shù),從array dic set 這些容器類型轉(zhuǎn)換為字符串微峰,具體轉(zhuǎn)碼方式可以使用自定義剥纷,也可以用AF默認(rèn)的轉(zhuǎn)碼方式涮毫。自定義的方式?jīng)]什么的由自己決定。下面看看默認(rèn)的方式:
NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutablePairs = [NSMutableArray array];
//把參數(shù)給AFQueryStringPairsFromDictionary贷屎,拿到AF的一個(gè)類型的數(shù)據(jù)就是一個(gè)key罢防,value對(duì)象,在URLEncodedStringValue拼接keyValue唉侄,一個(gè)加到數(shù)組里
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
}
//拆分?jǐn)?shù)組返回參數(shù)字符串
return [mutablePairs componentsJoinedByString:@"&"];
}
NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
//往下回調(diào)
return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
}
NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
//根據(jù)需要排列的對(duì)象的descript來進(jìn)行升序排列咒吐,并且selector使用的是compare:
//因?yàn)閷?duì)象的description返回的是NSString,所以此處的compare:使用的是NSString的compare函數(shù)
//即@[@"foo", @"bar", @"bae"] ----> @[@"bae", @"bar",@"foo"]
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
//判斷value是什么類型属划,然后去遞歸調(diào)用自己恬叹,知道解析的除了array,dic同眯,set以外的元素绽昼,然后把得到的參數(shù)數(shù)組返回。
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)];
}
}
} 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;
}
- 轉(zhuǎn)碼主要是以上三個(gè)函數(shù)须蜗,配合著注釋應(yīng)該也很好理解:主要是在遞歸調(diào)用
AFQueryStringPairsFromKeyAndValue
,判斷value是什么類型硅确,然后去遞歸調(diào)用自己,知道解析的是除了array明肮、dic菱农、set以外的元素,然后把得到了參數(shù)數(shù)組返回柿估。- 其中有個(gè)
AFQueryStringPair
對(duì)象循未,其中只有兩個(gè)屬性和兩個(gè)方法:
- 其中有個(gè)
@interface AFQueryStringPair : NSObject
@property (readwrite, nonatomic, strong) id field;
@property (readwrite, nonatomic, strong) id value;
- (instancetype)initWithField:(id)field value:(id)value;
- (NSString *)URLEncodedStringValue;
@end
@implementation AFQueryStringPair
- (instancetype)initWithField:(id)field value:(id)value {
self = [super init];
if (!self) {
return nil;
}
self.field = field;
self.value = value;
return self;
}
- (NSString *)URLEncodedStringValue {
if (!self.value || [self.value isEqual:[NSNull null]]) {
return AFPercentEscapedStringFromString([self.field description]);
} else {
return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedStringFromString([self.field description]), AFPercentEscapedStringFromString([self.value description])];
}
}
以上方法舉個(gè)例子梳理下:
@{
@"name" : @"bang",
@"phone": @{@"mobile": @"xx", @"home": @"xx"},
@"families": @[@"father", @"mother"],
@"nums": [NSSet setWithObjects:@"1", @"2", nil]
}
->
@[
field: @"name", value: @"bang",
field: @"phone[mobile]", value: @"xx",
field: @"phone[home]", value: @"xx",
field: @"families[]", value: @"father",
field: @"families[]", value: @"mother",
field: @"nums", value: @"1",
field: @"nums", value: @"2",
]
->
name=bang&phone[mobile]=xx&phone[home]=xx&families[]=father&families[]=mother&nums=1&num=2
至此,我們?cè)瓉淼娜萜黝愋偷膮?shù)秫舌,就這樣變成了字符串類型了的妖。
緊接著這個(gè)方法還根據(jù)request中的請(qǐng)求類型,來判斷參數(shù)字符串應(yīng)該如何設(shè)置到request中去足陨,如果是GET羔味、HEAD、DELETE钠右,則把參數(shù)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]];
}
至此飒房,我們生成了一個(gè)request搁凸。
我們?cè)倩氐紸FHTTPSessionManager類中來,回到這個(gè)方法: