研究AFN

NSURLSession

AFNHTTPSessionManager

AFHTTPSessionManager is a subclass of AFURLSessionManager with convenience methods for making HTTP requests. When a baseURL is provided, requests made with the GET / POST / et al. convenience methods can be made with relative paths.

在.h文件中

遵守NSSecureCoding, NSCopying協(xié)議

定義屬性

baseURL(NSURL),requestSerializer(AFHTTPRequestSerializer)陕习,responseSerializer(AFHTTPResponseSerializer)碳想。
1.初始化方法:
+ (instancetype)manager;
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
- (instancetype)initWithBaseURL:(nullable NSURL *)url sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
2.創(chuàng)建HTTP請(qǐng)求
主要是發(fā)送GET缩搅,POST(有無下載缺厉,downloadProgress是在Session queue中祭玉,不在主隊(duì)列)测暗,HEAD柜蜈,PUT,PATCH懊直,DELETE扒吁。
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(nullable id)parameters progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
只有POST請(qǐng)求有多種,需要加constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block將一個(gè)參數(shù)和拼接數(shù)據(jù)到HTTP主體室囊。該block參數(shù)是采用AFMultipartFormData協(xié)議的對(duì)象雕崩。

在.m文件中

主要是方法:

- (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) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }

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

所有的網(wǎng)絡(luò)請(qǐng)求都調(diào)用dataTaskWithHTTPMethod這個(gè)方法來實(shí)現(xiàn)。
實(shí)現(xiàn)了:

  1. NSObject中的description方法來打印出BaseURL融撞,session盼铁,和operationQueue。
  2. NSSecureCoding中的supportsSecureCoding尝偎,initWithCoder饶火,encodeWithCoder方法。
  3. NSCopying中的copyWithZone方法(HTTPClient)

AFURLSessionManager

AFURLSessionManager創(chuàng)建和管理一個(gè) NSURLSession 對(duì)象根據(jù)一個(gè)特殊的 NSURLSessionConfiguration 對(duì)象, 它符合<NSURLSessionTaskDelegate>, <NSURLSessionDataDelegate>, <NSURLSessionDownloadDelegate>, and <NSURLSessionDelegate>.

NSURLSession & NSURLSessionTask Delegate Methods:

NSURLSessionDelegate

- URLSession:didBecomeInvalidWithError:
- URLSession:didReceiveChallenge:completionHandler:
- URLSessionDidFinishEventsForBackgroundURLSession:

NSURLSessionTaskDelegate

-URLSession:willPerformHTTPRedirection:newRequest:completionHandler:
- URLSession:task:didReceiveChallenge:completionHandler:
-URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
- URLSession:task:needNewBodyStream:
- URLSession:task:didCompleteWithError:

NSURLSessionDataDelegate

  • URLSession:dataTask:didReceiveResponse:completionHandler:
  • URLSession:dataTask:didBecomeDownloadTask:
  • URLSession:dataTask:didReceiveData:
  • URLSession:dataTask:willCacheResponse:completionHandler:

NSURLSessionDownloadDelegate

  • URLSession:downloadTask:didFinishDownloadingToURL:
    -URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:
  • URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:

在.h文件中

遵守協(xié)議protocol為 <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>致扯,對(duì)應(yīng)相應(yīng)的代理方法肤寝。

定義屬性

1.session(NSURLSession),operationQueue(NSOperationQueue).responseSerializer(AFURLResponseSerialization)。
2.管理安全的策略:securityPolicy(AFSecurityPolicy).
3.管理檢測(cè)網(wǎng)絡(luò)的連通性:reachabilityManager(AFNetworkReachabilityManager).
4.獲得 Session Tasks:tasks抖僵,dataTasks,uploadTasks,downloadTasks.
5.管理回調(diào)的隊(duì)列:
completionQueue(dispatch_queue_t),completionGroup(dispatch_group_t).

定義方法:

  1. 初始化方法:
    - (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration;
    - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;

2.運(yùn)行Data Tasks:
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
3.運(yùn)行上傳任務(wù):
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
4.運(yùn)行下載任務(wù):
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
還有就是把NSURLRequest替換成NSData,
5.獲取任務(wù)的進(jìn)程(Getting Progress for Tasks):
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;還有downloadProgressForTask
6.設(shè)置Session的代理回調(diào)
- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

  1. 設(shè)置Task的代理回調(diào)
    - (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;
    - (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;
    - (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
    - (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;
    - (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;
    8.設(shè)置Data Task 的代理回調(diào)
    - (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block;
    - (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block;
    - (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;
    - (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;
    - (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block;
    9.設(shè)置Download Task的回調(diào)方法
    - (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
    - (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;
    - (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;
    10.設(shè)置通知Notification

在.m 文件中

主要有是三個(gè)@interface和@implement鲤看。
一個(gè)是AFURLSessionManagerTaskDelegate。
一個(gè)是_AFURLSessionTaskSwizzling裆针。
一個(gè)是AFURLSessionManager刨摩。

  1. AFURLSessionManagerTaskDelegate
    遵守協(xié)議<NSURLSessionTaskDelegate, NSURLSessionDataDelegate,NSURLSessionDownloadDelegate>寺晌,

NSProgress Tracking

- (void)setupProgressForTask:(NSURLSessionTask *)task
一部分是對(duì)代理持有的兩個(gè)屬性 uploadProgress和 downloadProgress設(shè)置回調(diào)

 self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    [self.uploadProgress setCancellable:YES];
    [self.uploadProgress setCancellationHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask cancel];
    }];
    [self.uploadProgress setPausable:YES];
    [self.uploadProgress setPausingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask suspend];
    }];
    if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
        [self.uploadProgress setResumingHandler:^{
            __typeof__(weakTask) strongTask = weakTask;
            [strongTask resume];
        }];
    }

設(shè)置上傳的取消暫停,下載一樣的道理澡刹。
另一個(gè)部分是對(duì) task 和 NSProgress的uploadProgress和downloadPreogress屬性進(jìn)行鍵值觀測(cè)呻征。
- (void)cleanUpProgressForTask:(NSURLSessionTask *)task
主要是移除download和upload的observer。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
主要是上面第一個(gè)函數(shù)中的實(shí)現(xiàn)NSURLSessionTask和NSURLSessionDownloadTask的類中下載和上傳的的接收和期望接收的字節(jié)數(shù)罢浇,發(fā)送和期望發(fā)送的字節(jié)數(shù)陆赋。改變進(jìn)度,并調(diào)用 block

NSURLSessionTaskDelegate

- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
如果遇到error嚷闭,dispatch_group_async攒岛,如果當(dāng)前 manager持有 completionGroup或者 completionQueue就在主線程中調(diào)用 completionHandler并發(fā)送通知(在主線程中)
如果在執(zhí)行當(dāng)前 task 時(shí)沒有遇到錯(cuò)誤,那么先對(duì)數(shù)據(jù)進(jìn)行序列化胞锰,然后同樣調(diào)用 block 并發(fā)送通知灾锯。

NSURLSessionDataTaskDelegate與NSURLSessionDownloadTaskDelegate

- (void)URLSession:(__unused NSURLSession *)session dataTask:(__unused NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
在收到數(shù)據(jù)后調(diào)用。并拼接data.
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
在下載完成對(duì)應(yīng)文件后調(diào)用嗅榕,并處理下載文件顺饮。如果fileManagerError,則發(fā)出通知凌那。

2._AFURLSessionTaskSwizzling
主要用到runtime的知識(shí)兼雄,來交換方法。修改 NSURLSessionTask的 resume和 suspend 方法帽蝶。這樣做的目的是為了在方法 resume或者 suspend被調(diào)用時(shí)發(fā)出通知赦肋。具體方法調(diào)劑過程是在 + load方法中進(jìn)行的.a.首先用 NSClassFromString(@"NSURLSessionTask")
判斷當(dāng)前部署的 iOS 版本是否含有類 NSURLSessionTask。b.因?yàn)?iOS7 和 iOS8 上對(duì)于 NSURLSessionTask的實(shí)現(xiàn)不同励稳,所以會(huì)通過 - [NSURLSession dataTaskWithURL:]方法返回一個(gè) NSURLSessionTask 實(shí)例佃乘。c .取得當(dāng)前類 _AFURLSessionTaskSwizzling 中的實(shí)現(xiàn) af_resume。d.如果當(dāng)前類 currentClass有 resume驹尼。
方法真:使用 swizzleResumeAndSuspendMethodForClass:調(diào)劑該類的 resume 和 suspend方法
假:currentClass = [currentClass superclass]

3.AFURLSessionManager(最重要的地方)
a.初始化在- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration中恕稠,初始化會(huì)話配置,設(shè)置為默認(rèn)的defaultSessionConfiguration扶欣,初始化會(huì)話session,并設(shè)置會(huì)話的代理和代理隊(duì)列千扶,初始化響應(yīng)序列化responseSerializer料祠,安全認(rèn)證securityPolicy,和監(jiān)控網(wǎng)絡(luò)狀態(tài)reachabilityManager澎羞。

b. 兩通知:- (void)taskDidResume:(NSNotification *)notification- (void)taskDidSuspend:(NSNotification *)notification

c.然后為NSURLSessionTask設(shè)置AFURLSessionManagerTaskDelegate髓绽,

- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task{
    NSParameterAssert(task);
    AFURLSessionManagerTaskDelegate *delegate = nil;
    [self.lock lock];
    delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
    [self.lock unlock];
    return delegate;
} ```
AFURLSessionManager就是通過字典 mutableTaskDelegatesKeyedByTaskIdentifier來存儲(chǔ)并管理每一個(gè) NSURLSessionTask,它以 taskIdentifier為鍵存儲(chǔ) task妆绞。該方法使用 NSLock
 來保證不同線程使用 mutableTaskDelegatesKeyedByTaskIdentifier時(shí)顺呕,不會(huì)出現(xiàn)**線程競(jìng)爭(zhēng)**的問題枫攀。

d.為DataTask加代理。
  • (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
    uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
    downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
    completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler```
    為uploadTask加代理,為downloadTask加代理株茶。移除代理方法
    - (void)removeDelegateForTask:(NSURLSessionTask *)task.
    用KVO檢測(cè)
    - (NSArray *)tasksForKeyPath:(NSString *)keyPath
    如果無效session来涨,則取消任務(wù):
    - (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks
    設(shè)置response的序列
    - (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerializer
    為任務(wù)添加(add)和移除(remove)通知觀察者.
    - (void)addNotificationObserverForTask:(NSURLSessionTask *)task

管理NSURLSessionTask

先調(diào)用

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler```
方法傳入NSURLRequest,
  • (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
    uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
    downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
    completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {

    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
    dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
    }```
    返回一個(gè) AFURLSessionManagerTaskDelegate對(duì)象启盛,將 completionHandler的
    uploadProgressBlock和 downloadProgressBlock 傳入該對(duì)象并在相應(yīng)事件發(fā)生時(shí)進(jìn)行回調(diào)
    然后

Reachability

AFNetworkReachabilityManager

主要是網(wǎng)絡(luò)的可用性蹦掐,類似于蘋果文檔的Reachability
AFNetworkReachabilityStatusUnknow= -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,

在.h文件中

先是初始化:
+ (instancetype)sharedManager;
+ (instancetype)manager;
+ (instancetype)managerForDomain:(NSString *)domain;
+ (instancetype)managerForAddress:(const void *)address;
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
然后開始或停止可用性的監(jiān)控:
- (void)startMonitoring;
- (void)stopMonitoring;
- (NSString *)localizedNetworkReachabilityStatusString;
再設(shè)置網(wǎng)絡(luò)可用性來改變回調(diào):
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
最后是一些常量,通知和功能僵闯。

在.m文件中:

初始化:
+ (instancetype)sharedManager中用dispatch_once卧抗,調(diào)用+ (instancetype)manager,

+ (instancetype)managerForDomain:(NSString *)domain {
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
    AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    CFRelease(reachability);
    return manager;
}
+ (instancetype)managerForAddress:(const void *)address {
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
    AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    CFRelease(reachability);   
    return manager;
}```
1. 使用 SCNetworkReachabilityCreateWithAddress或者 SCNetworkReachabilityCreateWithName生成一個(gè) SCNetworkReachabilityRef的引用。
2. 兩個(gè)方法會(huì)通過一個(gè)**域名**或者一個(gè) sockaddr_in的指針生個(gè) SCNetworkReachabilityRef鳖粟。
3. 調(diào)用 `- [AFNetworkReachabilityManager initWithReachability:] `將生成的 SCNetworkReachabilityRef引用傳給networkReachability.
4. 當(dāng)調(diào)用 CFBridgingRelease(reachability)后社裆,會(huì)把 reachability橋接成一個(gè) NSObject 對(duì)象賦值給self.networkReachability,然后釋放原來的 CoreFoundation 對(duì)象向图。

  • (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
    self = [super init];
    if (!self) {
    return nil;
    }
    _networkReachability = CFRetain(reachability);
    self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
    return self;
    }
監(jiān)控網(wǎng)絡(luò)狀態(tài):
  • (void)startMonitoring {
    [self stopMonitoring];
    if (!self.networkReachability) {
    return;
    }
    __weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    __strong __typeof(weakSelf)strongSelf = weakSelf;
    strongSelf.networkReachabilityStatus = status;
    if (strongSelf.networkReachabilityStatusBlock) {
    strongSelf.networkReachabilityStatusBlock(status);
    }
    };
    SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
    SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
    SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
    SCNetworkReachabilityFlags flags;
    if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
    AFPostReachabilityStatusChange(flags, callback);
    }
    });
    }
  • (void)stopMonitoring {
    if (!self.networkReachability) {
    return;
    }
    SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    }
1. 先調(diào)用 - stopMonitoring方法泳秀,如果之前設(shè)置過對(duì)網(wǎng)絡(luò)狀態(tài)的監(jiān)聽,使用SCNetworkReachabilityUnscheduleFromRunLoop方法取消之前在 Main Runloop 中的監(jiān)聽.
2. 創(chuàng)建一個(gè)在每次網(wǎng)絡(luò)狀態(tài)改變時(shí)的回調(diào)block张漂,每次回調(diào)被調(diào)用時(shí)晶默,重新設(shè)置networkReachabilityStatus的屬性,調(diào)用networkReachabilityStatus航攒,
3. 創(chuàng)建一個(gè)SCNetworkReachabilityContext磺陡,其中的 callback就是上一步中的創(chuàng)建的 block 對(duì)象。這里的 AFNetworkReachabilityRetainCallback 和 AFNetworkReachabilityReleaseCallback
 都是非常簡(jiǎn)單的 block漠畜,在回調(diào)被調(diào)用時(shí)币他,只是使用 Block_copy和 Block_release
 這樣的宏。傳入的 info
 會(huì)以參數(shù)的形式在 AFNetworkReachabilityCallback
 執(zhí)行時(shí)傳入
static const void * AFNetworkReachabilityRetainCallback(const void *info) { return Block_copy(info); }
static void AFNetworkReachabilityReleaseCallback(const void *info) { if (info) { Block_release(info); } }
4. 當(dāng)目標(biāo)的網(wǎng)絡(luò)狀態(tài)改變時(shí)憔狞,會(huì)調(diào)用傳入的回調(diào)
5. 在 Main Runloop 中對(duì)應(yīng)的模式開始監(jiān)控網(wǎng)絡(luò)狀態(tài)蝴悉。
6. 取當(dāng)前的網(wǎng)絡(luò)狀態(tài),調(diào)用 callback
其中`  SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);`回調(diào)了AFNetworkReachabilityManager的AFNetworkReachabilityCallback瘾敢。
總結(jié):
AFNetworkReachabilityManager實(shí)際上只是一個(gè)對(duì)底層 SystemConfiguration庫(kù)中的 C 函數(shù)封裝的類拍冠,它為我們隱藏了 C 語言的實(shí)現(xiàn),提供了統(tǒng)一的 Objective-C 語言接口簇抵。
它是 AFNetworking中一個(gè)即插即用的模塊

# Security
## AFSecurityPolicy
為了阻止中間人攻擊庆杜,以及其它漏洞的工具。

用枚舉設(shè)置了驗(yàn)證服務(wù)器被信任的方式SSL的類型有None碟摆,PublicKey晃财,還有Certificate。
AFSSLPinningModeNone是默認(rèn)的認(rèn)證方式典蜕,只會(huì)在系統(tǒng)的信任的證書列表中對(duì)服務(wù)端返回的證書進(jìn)行驗(yàn)證
AFSSLPinningModeCertificate需要客戶端預(yù)先保存服務(wù)端的證書
AFSSLPinningModePublicKey也需要預(yù)先保存服務(wù)端發(fā)送的證書断盛,但是這里只會(huì)驗(yàn)證證書中的公鑰是否正確
遵守<NSSecureCoding, NSCopying>罗洗。
### 從bundle獲取證書,并返回
`+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;`
###  獲取特殊的安全策略
`+ (instancetype)defaultPolicy;`
###  初始化
`+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;`
`+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;`
初始化方法時(shí),主要目的是設(shè)置**驗(yàn)證服務(wù)器是否受信任的方式**钢猛。
### 驗(yàn)證服務(wù)端是否信任

  • (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
    forDomain:(NSString *)domain
    {
    if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
    NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
    return NO;
    }
    NSMutableArray *policies = [NSMutableArray array];
    if (self.validatesDomainName) {
    [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
    } else {
    [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
    }
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
    if (self.SSLPinningMode == AFSSLPinningModeNone) {
    return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
    } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
    return NO;
    }
    switch (self.SSLPinningMode) {
    case AFSSLPinningModeNone:
    default:
    return NO;
    case AFSSLPinningModeCertificate: {
    NSMutableArray *pinnedCertificates = [NSMutableArray array];
    for (NSData *certificateData in self.pinnedCertificates) {
    [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
    }
    SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);

          if (!AFServerTrustIsValid(serverTrust)) {
              return NO;
          }
          // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
          NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);            
          for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
              if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                  return YES;
              }
          }         
          return NO;
      }
      case AFSSLPinningModePublicKey: {
          NSUInteger trustedPublicKeyCount = 0;
          NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
          for (id trustChainPublicKey in publicKeys) {
              for (id pinnedPublicKey in self.pinnedPublicKeys) {
                  if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                      trustedPublicKeyCount += 1;
                  }
              }
          }
          return trustedPublicKeyCount > 0;
      }
    

    }
    return NO;
    }```

  1. 所以如果沒有提供證書或者不驗(yàn)證證書伙菜,并且還設(shè)置 allowInvalidCertificates為,滿足上面的所有條件厢洞,說明這次的驗(yàn)證是不安全的仇让,會(huì)直接返回 NO.
  2. 設(shè)置 policy:如果要驗(yàn)證域名的話,就以域名為參數(shù)創(chuàng)建一個(gè) SecPolicyRef躺翻,否則會(huì)創(chuàng)建一個(gè)符合 X509 標(biāo)準(zhǔn)的默認(rèn)SecPolicyRef對(duì)象
  3. 驗(yàn)證證書的有效性:如果只根據(jù)信任列表中的證書進(jìn)行驗(yàn)證丧叽,即 self.SSLPinningMode == AFSSLPinningModeNone
    。如果允許無效的證書的就會(huì)直接返回 YES
    公你。不允許就會(huì)對(duì)服務(wù)端信任進(jìn)行驗(yàn)證踊淳。
    如果服務(wù)器信任無效,并且不允許無效證書陕靠,就會(huì)返回 NO.
  4. 根據(jù) SSLPinningMode對(duì)服務(wù)器信任進(jìn)行驗(yàn)證
    AFSSLPinningModeNone直接返回 NO
    AFSSLPinningModeCertificate
    AFSSLPinningModePublicKey

Serialization

對(duì)發(fā)出請(qǐng)求以及接收響應(yīng)的過程進(jìn)行序列化迂尝,這涉及到兩個(gè)模塊

AFURLRequestSerialization

修改請(qǐng)求(主要是 HTTP 請(qǐng)求)的頭部,提供了一些語義明確的接口設(shè)置 HTTP 頭部字段剪芥。
主要用于 AFHTTPSessionManager中垄开,因?yàn)樗饕糜?strong>修改 HTTP 頭部。

AFURLResponseSerialization(重要)

處理響應(yīng)的模塊税肪,將請(qǐng)求返回的數(shù)據(jù)解析成對(duì)應(yīng)的格式.這個(gè)模塊使用在 AFURLSessionManager
也就是核心類溉躲。其實(shí)也只是個(gè)協(xié)議
@protocol AFURLResponseSerialization <NSObject, NSSecureCoding, NSCopying>
遵循這個(gè)協(xié)議的類同時(shí)也要遵循 NSObject、NSSecureCoding 和 NSCopying 這三個(gè)協(xié)議益兄,實(shí)現(xiàn)安全編碼锻梳、拷貝以及 Objective-C 對(duì)象的基本行為。
這個(gè)協(xié)議只有一個(gè)必須實(shí)現(xiàn)的方法:

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;```
在.h文件中中有7個(gè)類:
 第一個(gè)
`@interface AFHTTPResponseSerializer : NSObject <AFURLResponseSerialization>`剩下的六個(gè)AFJSONResponseSerializer净捅,AFXMLParserResponseSerializer疑枯,AFXMLDocumentResponseSerializer,AFPropertyListResponseSerializer蛔六,AFImageResponseSerializer荆永,AFCompoundResponseSerializer都繼承自AFHTTPResponseSerializer。
### AFHTTPResponseSerializer
先看一下AFHTTPResponseSerializer的實(shí)現(xiàn):
  • (instancetype)serializer {
    return [[self alloc] init];
    }
  • (instancetype)init {
    self = [super init];
    if (!self) {
    return nil;
    }
    self.stringEncoding = NSUTF8StringEncoding;
    self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
    self.acceptableContentTypes = nil;
    return self;
    }
因?yàn)槭菍?duì) HTTP 響應(yīng)進(jìn)行序列化国章,所以這里設(shè)置了 stringEncoding為 NSUTF8StringEncoding而且沒有對(duì)接收的內(nèi)容類型加以限制屁魏。
將 acceptableStatusCodes設(shè)置為從 200 到 299 之間的狀態(tài)碼, 因?yàn)橹挥羞@些狀態(tài)碼表示**獲得了有效的響應(yīng)**
驗(yàn)證響應(yīng)的有效性:
  • (BOOL)validateResponse:(NSHTTPURLResponse *)response
    data:(NSData *)data
    error:(NSError * __autoreleasing *)error
    {
    BOOL responseIsValid = YES;
    NSError *validationError = nil;
    if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
    if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
    !([response MIMEType] == nil && [data length] == 0)) {
    if ([data length] > 0 && [response URL]) {
    NSMutableDictionary *mutableUserInfo = [@{
    NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
    NSURLErrorFailingURLErrorKey:[response URL], AFNetworkingOperationFailingURLResponseErrorKey: response,
    } mutableCopy];
    if (data) {
    mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
    }
    validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
    }
    responseIsValid = NO;
    }
    if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
    NSMutableDictionary *mutableUserInfo = [@{
    NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
    NSURLErrorFailingURLErrorKey:[response URL],
    AFNetworkingOperationFailingURLResponseErrorKey: response,
    } mutableCopy];
    if (data) {
    mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
    }
    validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
    responseIsValid = NO;
    }
    }
    if (error && !responseIsValid) {
    *error = validationError;
    }
    return responseIsValid;
    }```
    這個(gè)方法根據(jù)在初始化方法中初始化的屬性 acceptableContentTypes 和 acceptableStatusCodes來判斷當(dāng)前響應(yīng)是否有效。

AFURLResponseSerialization協(xié)議的實(shí)現(xiàn)

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error{
[self validateResponse:(NSHTTPURLResponse *)response data:data error:error];
    return data;
}```
主要是調(diào)用上面的方法對(duì)響應(yīng)進(jìn)行驗(yàn)證捉腥,然后返回?cái)?shù)據(jù),實(shí)在是沒什么難度你画。
1. NSSecureCoding
對(duì)安全協(xié)議的實(shí)現(xiàn)抵碟,就是支持安全編碼桃漾,根據(jù)屬性acceptableStatusCodes,acceptableContentTypes然后初始化拟逮,然后encode
2. NSCopying
實(shí)現(xiàn)copy屬性
### AFJSONResponseSerializer
初始化方法只是在調(diào)用父類的初始化方法之后更新了 acceptableContentTypes
 屬性:

  • (instancetype)init {
    self = [super init];
    if (!self) {
    return nil;
    }
    self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];
    return self;
    }```
    這個(gè)類中與父類差別最大的就是對(duì) AFURLResponseSerialization協(xié)議的實(shí)現(xiàn)撬统。
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(
NSError *__autoreleasing *)error
{ 
#1: 驗(yàn)證請(qǐng)求
 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }
 #2: 解決一個(gè)由只包含一個(gè)空格的響應(yīng)引起的 bug, 略
 #3: 序列化 JSON
  id responseObject = nil;
    NSError *serializationError = nil;
    // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
    // See https://github.com/rails/rails/issues/1742
    BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
    if (data.length > 0 && !isSpace) {
        responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
    } else {
        return nil;
    }
    if (self.removesKeysWithNullValues && responseObject) {
        responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
    }
#4: 移除 JSON 中的 null 
if (error) { 
*error = AFErrorWithUnderlyingError(serializationError, *error); } 
return responseObject;
}```
然后實(shí)現(xiàn)NSSecureCoding,NSCopying與上面類似
其他幾個(gè)子類實(shí)現(xiàn)差不多敦迄。
## AFURLRequestSerialization
AFURLRequestSerialization的主要工作是對(duì)發(fā)出的 HTTP 請(qǐng)求進(jìn)行處理恋追,它有幾部分的工作需要完成。
而這個(gè)文件中的大部分類都是為 AFHTTPRequestSerializer服務(wù)的:
1. 處理查詢的 URL 參數(shù)
2. 設(shè)置 HTTP 頭部字段
3. 設(shè)置請(qǐng)求的屬性
4. 分塊上傳
### 處理查詢參數(shù)
處理查詢參數(shù)這部分主要是通過 AFQueryStringPair還有一些 C 函數(shù)來完成的罚屋,這個(gè)類有兩個(gè)屬性 field和 value對(duì)應(yīng) HTTP 請(qǐng)求的查詢 URL 中的參數(shù)苦囱。在.m文件中,先是它的實(shí)現(xiàn)脾猛。

@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
其中URLEncodedStringValue方法會(huì)返回
`return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedStringFromString([self.field description]), AFPercentEscapedStringFromString([self.value description])];`
key=value這種格式撕彤,同時(shí)使用 AFPercentEscapedStringFromString函數(shù)來對(duì) field和 value進(jìn)行處理,將其中的 :#[]@!$&'()*+,;=等字符轉(zhuǎn)換為百分號(hào)表示的形式猛拴。
這一部分代碼還負(fù)責(zé)返回查詢參數(shù)羹铅,將 AFQueryStringPair中key和value
 轉(zhuǎn)換為以下這種形式:
username=tom&password=123456&hello[world]=helloworld
下面是用FOUNDATION_EXPORT定義的NSArray的數(shù)組,有AFQueryStringPairsFromDictionary愉昆,AFQueryStringPairsFromKeyAndValue职员,AFQueryStringFromParameters,AFQueryStringPairsFromDictionary跛溉,AFQueryStringPairsFromKeyAndValue焊切。
它的實(shí)現(xiàn)主要依賴于一個(gè)遞歸函數(shù) AFQueryStringPairsFromKeyAndValue,如果當(dāng)前的 value
 是一個(gè)集合類型的話倒谷,那么它就會(huì)不斷地遞歸調(diào)用自己蛛蒙。

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) {
[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;
}

返回一個(gè)數(shù)組
[ username=tom, password=123456, hello[world]=helloworld]
得到這個(gè)數(shù)組之后就會(huì)調(diào)用 AFQueryStringFromParameters使用 &來拼接它們。

NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
}
return [mutablePairs componentsJoinedByString:@"&"];
}```

  1. 設(shè)置請(qǐng)求的屬性
    這個(gè)下面有一個(gè)AFStreamingMultipartFormData的聲明渤愁,是多形式的數(shù)據(jù)流牵祟。
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;
}```
在這些屬性被設(shè)置時(shí),會(huì)觸發(fā) KVO抖格,然后將新的屬性存儲(chǔ)在一個(gè)名為 mutableObservedChangedKeyPaths的字典中:

  • (void)observeValueForKeyPath:(NSString *)keyPath
    ofObject:(__unused id)object
    change:(NSDictionary *)change
    context:(void *)context
    {
    if (context == AFHTTPRequestSerializerObserverContext) {
    if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
    [self.mutableObservedChangedKeyPaths removeObject:keyPath];
    } else {
    [self.mutableObservedChangedKeyPaths addObject:keyPath];
    }
    }
    }```
    然后會(huì)在生成NSURLRequest的時(shí)候設(shè)置這些屬性:
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    mutableRequest.HTTPMethod = method;
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }
  1. 設(shè)置HTTP頭部字段
    在AFHTTPRequestSerializer的interface文件中提供了一些屬性方便我們?cè)O(shè)置 HTTP 頭部字段
    mutableHTTPRequestHeaders.
- (NSDictionary *)HTTPRequestHeaders {
//在設(shè)置 HTTP 頭部字段時(shí)诺苹,都會(huì)存儲(chǔ)到這個(gè)可變字典中。而當(dāng)真正使用時(shí)雹拄,用這個(gè)方法收奔,來獲取對(duì)應(yīng)版本的不可變字典。
    return [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
}
- (void)setValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
{
    [self.mutableHTTPRequestHeaders setValue:value forKey:field];
}
- (NSString *)valueForHTTPHeaderField:(NSString *)field {
    return [self.mutableHTTPRequestHeaders valueForKey:field];
}

這個(gè)類是如何設(shè)置一些我們平時(shí)常用的頭部字段的滓玖。首先是 User-Agent坪哄,AFHTTPRequestSerializer剛剛初始化時(shí),就會(huì)根據(jù)當(dāng)前編譯的平臺(tái)生成一個(gè) userAgent。在iOS翩肌,ios_watch還有iOS_VERSION_MIN的平臺(tái)下生成不同模暗。
之后有方法設(shè)置授權(quán)頭部用用戶名和密碼,還有清除方法:

- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
                                       password:(NSString *)password
{
    NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
    NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
    [self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"];
}
- (void)clearAuthorizationHeader {
    [self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
}```
設(shè)置了AFHTTPBodyPart念祭,AFMultipartBodyStream的@interface兑宇。

 字符串:
#UIKit+AFNetworking

參考:
[源碼解析](https://github.com/Draveness/iOS-Source-Code-Analyze/blob/master/AFNetworking/%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82%E5%92%8C%E5%93%8D%E5%BA%94%20AFURLSerialization%EF%BC%88%E4%B8%89%EF%BC%89.md)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市粱坤,隨后出現(xiàn)的幾起案子隶糕,更是在濱河造成了極大的恐慌,老刑警劉巖站玄,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枚驻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蜒什,警方通過查閱死者的電腦和手機(jī)测秸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灾常,“玉大人霎冯,你說我怎么就攤上這事〕伲” “怎么了沈撞?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)雕什。 經(jīng)常有香客問我缠俺,道長(zhǎng),這世上最難降的妖魔是什么贷岸? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任壹士,我火速辦了婚禮,結(jié)果婚禮上偿警,老公的妹妹穿的比我還像新娘躏救。我一直安慰自己,他們只是感情好螟蒸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布盒使。 她就那樣靜靜地躺著,像睡著了一般七嫌。 火紅的嫁衣襯著肌膚如雪少办。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天诵原,我揣著相機(jī)與錄音英妓,去河邊找鬼挽放。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鞋拟,可吹牛的內(nèi)容都是我干的骂维。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼贺纲,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了褪测?” 一聲冷哼從身側(cè)響起猴誊,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侮措,沒想到半個(gè)月后懈叹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡分扎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年澄成,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畏吓。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡墨状,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菲饼,到底是詐尸還是另有隱情肾砂,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布宏悦,位于F島的核電站镐确,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏饼煞。R本人自食惡果不足惜源葫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望砖瞧。 院中可真熱鬧息堂,春花似錦、人聲如沸芭届。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褂乍。三九已至持隧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逃片,已是汗流浹背屡拨。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工只酥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呀狼。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓裂允,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親哥艇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绝编,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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