先看一下afnetworking
的目錄結構:
大家都看見了網絡請求其實有兩種方式。一種是用AFHTTPRequestOperationManager
,另一種是用AFHTTPSessionManager
捂寿。那么這兩種有什么區(qū)別尼患整?
可能有人有所不知勺择,AFNetworking
最初的版本使用的就是AFHTTPRequestOperationManager
以就是自己自定義NSOperation
的封裝實現(xiàn)的草雕。AFHTTPSessionManager
是在2.0
以后才引入進來的。以就是說在2.0
之前赃梧,都是使用AFHTTPRequestOperationManager
滤蝠。
AFHTTPSessionManager
繼承自 AFURLSessionManager
,而AFURLSessionManager
主要是使用系統(tǒng)提供的 NSURLSession
和NSURLSessionTask
進行網絡操作的授嘀。我們看一下官方文檔對這兩個類的描述:
NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0)
@interface NSURLSession : NSObject
/*
* NSURLSessionTask - a cancelable object that refers to the lifetime
* of processing a given request.
*/
NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0)
@interface NSURLSessionTask : NSObject <NSCopying>
是的物咳,你沒有看錯,NSURLSession
和NSURLSessionTask
是iOS7
以后才出現(xiàn)的蹄皱,所以如果你想要適配到iOS6
览闰,那么請你乖乖的使用前者 進行網絡請求芯肤。這就解釋了為什么作者會把兩種請求方式都放在這兒。
下面分兩部分進行網絡AFNetworking
網絡請求的分析:
AFHTTPRequestOperationManager
部分的網絡請求原理:
AFHTTPRequestOperationManager
的init
方法是這樣的:
- (instancetype)initWithBaseURL:(NSURL *)url {
self = [super init];
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];
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
self.operationQueue = [[NSOperationQueue alloc] init];
self.shouldUseCredentialStorage = YES;
return self;
}
其中默認的請求方式和解析方式被設置了默認值:
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
當然用戶可以修改這兩個參數(shù)压鉴,指定自己的請求方式和解析方式崖咨。
下面以GET
請求為例來說。
當用戶發(fā)起一個GET
請求油吭,下面的方法會被掉用:
- (AFHTTPRequestOperation *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
其中[self.operationQueue addOperation:operation];
就是將當前的任務放進操作隊列击蹲。
關鍵我們看看AFHTTPRequestOperation
里面都做了什么。
AFHTTPRequestOperation
是繼承自AFURLConnectionOperation
婉宰,AFURLConnectionOperation
實現(xiàn)了各種代理:
@interface AFURLConnectionOperation : NSOperation <NSURLConnectionDelegate, NSURLConnectionDataDelegate, NSSecureCoding, NSCopying>
我們知道當一個operation
任務被啟動的時候start
方法就會被調用:
- (void)start {
[self.lock lock];
if ([self isCancelled]) {
[self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
} else if ([self isReady]) {
self.state = AFOperationExecutingState;
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}
- (void)operationDidStart {
[self.lock lock];
if (![self isCancelled]) {
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}
[self.outputStream open];
[self.connection start];
}
[self.lock unlock];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
});
}
我們分析一下以上代碼塊歌豺,當AFURLConnectionOperation
任務被正常啟動的時候,下面的方法會被調用:
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
operationDidStart方法會在[[self class] networkRequestThread]返回的線程中被調用心包。我們看看這是一個什么樣的線程:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
是的這個新的小線程命名為"AFNetworking", 它在創(chuàng)建的時候就啟動了一個人runloop
事件循環(huán)类咧,并添加了一個NSMachPort
空端口,改NSMachPort
僅僅只是一個空的端口其目的是用來維護runloop
的執(zhí)行不被退出谴咸。
operationDidStart
方法中的:
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}
[self.outputStream open];
[self.connection start];
說明self.connection
和self.outputStream
周期性任務被綁定在當期的runloop
的self.runLoopModes
模式中轮听。(self.runLoopModes
在初始化的時候被賦值為[NSSet setWithObject:NSRunLoopCommonModes]
)
行了骗露,那么當網絡請求數(shù)據(jù)到達的時候岭佳,數(shù)據(jù)是如何被接收到的尼,我想這一點才是大家最關心的萧锉。
網絡請求是一個異步的過程珊随,當網絡請求數(shù)據(jù)流到達的時候,runloop
監(jiān)聽到該事件源__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
方法會被調用柿隙。之后CFNetwork
的_NSURLConnectionDidReceiveData(_CFURLConnection*, __CFData const*, long, void const*)
放會被調用獲取到網絡數(shù)據(jù)叶洞。與此同時NSURLConnectionInternal
的_withActiveConnectionAndDelegate
方法會被調用,本地代理被激活禀崖。AFURLConnectionOperation
中的代理方法:
- (void)connection:(NSURLConnection __unused *)connection
didReceiveData:(NSData *)data
{
NSUInteger length = [data length];
while (YES) {
NSInteger totalNumberOfBytesWritten = 0;
if ([self.outputStream hasSpaceAvailable]) {
const uint8_t *dataBuffer = (uint8_t *)[data bytes];
NSInteger numberOfBytesWritten = 0;
while (totalNumberOfBytesWritten < (NSInteger)length) {
numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
if (numberOfBytesWritten == -1) {
break;
}
totalNumberOfBytesWritten += numberOfBytesWritten;
}
break;
} else {
[self.connection cancel];
if (self.outputStream.streamError) {
[self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError];
}
return;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
self.totalBytesRead += (long long)length;
if (self.downloadProgress) {
self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength);
}
});
}
被調用衩辟,通過以上代碼中的:
NSInteger numberOfBytesWritten = 0;
while (totalNumberOfBytesWritten < (NSInteger)length) {
numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
if (numberOfBytesWritten == -1) {
break;
}
totalNumberOfBytesWritten += numberOfBytesWritten;
}
網絡數(shù)據(jù)流被寫入緩存。數(shù)據(jù)被寫入緩存完成后波附,代理方法:
- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
[self.outputStream close];
if (self.responseData) {
self.outputStream = nil;
}
self.connection = nil;
[self finish];
}
會被調用后艺晴。我們追蹤[self finish];
看看它里面的實現(xiàn):
- (void)finish {
[self.lock lock];
self.state = AFOperationFinishedState;
[self.lock unlock];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
});
}
self.state = AFOperationFinishedState
這句代碼是重點,它標示了該請求任務已經結束掸屡。而這句賦值還做了一個KVO的操作封寞,如下代碼:
- (void)setState:(AFOperationState)state {
if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
return;
}
[self.lock lock];
NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
NSString *newStateKey = AFKeyPathFromOperationState(state);
[self willChangeValueForKey:newStateKey];
[self willChangeValueForKey:oldStateKey];
_state = state;
[self didChangeValueForKey:oldStateKey];
[self didChangeValueForKey:newStateKey];
[self.lock unlock];
}
NSOperationInternal
中的_observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:
方法會監(jiān)聽state
狀態(tài)的改變。然后回歸到主線程仅财,AFURLConnectionOperation中的setCompletionBlock
方法被回調:
- (void)setCompletionBlock:(void (^)(void))block {
[self.lock lock];
if (!block) {
[super setCompletionBlock:nil];
} else {
__weak __typeof(self)weakSelf = self;
[super setCompletionBlock:^ {
__strong __typeof(weakSelf)strongSelf = weakSelf;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop
dispatch_group_async(group, queue, ^{
block();
});
dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
[strongSelf setCompletionBlock:nil];
});
}];
}
[self.lock unlock];
}
關鍵看這句代碼:
dispatch_group_async(group, queue, ^{
block();
});
block()
一調用就調用到了AFHTTPRequestOperation
的方法:
#pragma mark - AFHTTPRequestOperation
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^{
if (self.completionGroup) {
dispatch_group_enter(self.completionGroup);
}
dispatch_async(http_request_operation_processing_queue(), ^{
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
id responseObject = self.responseObject;
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
if (success) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
success(self, responseObject);
});
}
}
}
if (self.completionGroup) {
dispatch_group_leave(self.completionGroup);
}
});
};
#pragma clang diagnostic pop
}
self.completionBlock
中的內容被執(zhí)行狈究,這里面最關鍵的一句id responseObject = self.responseObject
獲得了解析數(shù)據(jù),我們看看self.responseObject
的實現(xiàn):
- (id)responseObject {
[self.lock lock];
if (!_responseObject && [self isFinished] && !self.error) {
NSError *error = nil;
self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
if (error) {
self.responseSerializationError = error;
}
}
[self.lock unlock];
return _responseObject;
}
我靠盏求!春天來了抖锥,這句代碼:
self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
將stream
中的數(shù)據(jù)解析成了我們想要數(shù)據(jù)比如json亿眠、xml、plist
等等磅废。然后AFHTTPRequestOperation
方法setCompletionBlockWithSuccess
中代碼success(self, responseObject)
一回調缕探。好了,現(xiàn)在就不用說了还蹲,我們通常就是在這個success
block
做我們自己的處理的爹耗。
下面我們看一下AFHTTPSessionManager
網絡請求是怎么樣進行的
蘋果已經對NSURLSessionDataTask
做了高度的封裝,類似于AFURLConnectionOperation
這樣的復雜封裝已經看不見了谜喊。但是原理跟AFURLConnectionOperation
的差不多這里就不在贅述了潭兽。
到一個網絡數(shù)據(jù)流到達的時候,NSURLSession的URLSession:dataTask:didReceiveData:
方法就會被激活斗遏。AFURLSessionManager
實現(xiàn)了NSURLSession
的代理山卦,于是乎AFURLSessionManager
中的代理方法就會被調用:
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}
[delegate URLSession:session dataTask:dataTask didReceiveData:data]
里面的實現(xiàn)四這樣的:
- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
[self.mutableData appendData:data];
}
這樣網絡數(shù)據(jù)就被寫入了self.mutableData
。
當數(shù)據(jù)獲取完成之后URLSession:task:didCompleteWithError:
方法就會被調用:
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
我們看看 [delegate URLSession:session task:task didCompleteWithError:error]
方法中的實現(xiàn):
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
//Performance Improvement from #2672
NSData *data = nil;
if (self.mutableData) {
data = [self.mutableData copy];
//We no longer need the reference, so nil it out to gain back some memory.
self.mutableData = nil;
}
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, error);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
} else {
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
if (self.downloadFileURL) {
responseObject = self.downloadFileURL;
}
if (responseObject) {
userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
}
if (serializationError) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
}
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
#pragma clang diagnostic pop
}
以上代碼中 data = [self.mutableData copy]
可知網絡數(shù)據(jù)流被copy
到了 data
之中诵次,關鍵代碼:
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError]
網絡數(shù)據(jù)被解析成了我們最終獲取到的數(shù)據(jù)账蓉。self.completionHandler
一執(zhí)行如下代碼塊:
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
就回到了AFHTTPSessionManager
的方法:
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
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 completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
這block
就會被調用:
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
這里的success
和 failure
就是我們經常看見的回調方法逾一。