龜速學(xué)習(xí)AFNetworking--01

前言

學(xué)習(xí)一下大神的編碼思想是很有必要的,另外用了怎么久的開源庫不認(rèn)真對(duì)待有點(diǎn)說不過去箍邮。這里借助部分博客以及源碼來學(xué)習(xí)恋博。如有不足,多多指點(diǎn)涨冀!

目錄

  • AFNetworking架構(gòu)及主要模塊的功能
  • AFNetworking具體模塊的探究

AFNetworking架構(gòu)及主要模塊的功能

AFNetworking的導(dǎo)入這里就不多介紹填硕,直接放目錄


屏幕快照 2017-09-22 17.03.55.png

可以清楚的看到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)系。除去后
屏幕快照 2017-09-22 17.29.58.png

其中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è)方法:
@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è)方法:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狠毯,一起剝皮案震驚了整個(gè)濱河市护糖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嚼松,老刑警劉巖嫡良,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锰扶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡寝受,警方通過查閱死者的電腦和手機(jī)坷牛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來很澄,“玉大人京闰,你說我怎么就攤上這事∷粒” “怎么了蹂楣?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)讯蒲。 經(jīng)常有香客問我痊土,道長(zhǎng),這世上最難降的妖魔是什么墨林? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任赁酝,我火速辦了婚禮,結(jié)果婚禮上萌丈,老公的妹妹穿的比我還像新娘。我一直安慰自己雷则,他們只是感情好辆雾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著月劈,像睡著了一般度迂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上猜揪,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天惭墓,我揣著相機(jī)與錄音,去河邊找鬼而姐。 笑死腊凶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拴念。 我是一名探鬼主播钧萍,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼政鼠!你這毒婦竟也來了风瘦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤公般,失蹤者是張志新(化名)和其女友劉穎万搔,沒想到半個(gè)月后胡桨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞬雹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年昧谊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挖炬。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡揽浙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出意敛,到底是詐尸還是另有隱情馅巷,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布草姻,位于F島的核電站钓猬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏撩独。R本人自食惡果不足惜敞曹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望综膀。 院中可真熱鬧澳迫,春花似錦、人聲如沸剧劝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讥此。三九已至拢锹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萄喳,已是汗流浹背卒稳。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留他巨,地道東北人充坑。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像染突,于是被迫代替她去往敵國(guó)和親匪傍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 寫在開頭: 作為一個(gè)iOS開發(fā),也許你不知道NSUrlRequest薪棒、不知道NSUrlConnection手蝎、也不知...
    涂耀輝閱讀 98,694評(píng)論 172 1,346
  • 接著上一篇的內(nèi)容往下講棵介,如果沒看過上一篇內(nèi)容可以點(diǎn)這: AFNetworking到底做了什么? 之前我們講到NSU...
    涂耀輝閱讀 21,167評(píng)論 28 160
  • AFNetworking基本每個(gè)項(xiàng)目都會(huì)用钉鸯。但是看它的代碼的人不多。有一次面試邮辽,面試官問我看過AFNetworki...
    charlotte2018閱讀 936評(píng)論 1 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理唠雕,服務(wù)發(fā)現(xiàn),斷路器吨述,智...
    卡卡羅2017閱讀 134,652評(píng)論 18 139
  • 一個(gè)十八歲的大學(xué)生問我岩睁,上大學(xué)有什么用?
    沉香荷閱讀 193評(píng)論 0 0