iOS開源專案學習—— AFNetworking
網路上已有對AFNetworking的很好的分析,如:
對於AFNetworking的詳細介紹,可以參考作者Mattt Thompson的在AFNetworking 2.0的介紹。
NSURLConnection
- AFURLConnectionOperation繼承自NSOperation,並實現了NSURLConnection的代理方法。它是所有網路請求操作的基類。
- AFHTTPRequestOperation繼承自AFURLConnectionOperation,使用HTTP或者HTTPS來進行請求。它封裝了acceptable status codes 和content types的型別,這是用來確定一個請求失敗或成功的。
- AFHTTPRequestOperationManager封裝了web應用通過HTTP請求的通用模式,包括請求的建立、響應的序列化,網路狀態的監控和安全,以及網路請求的管理。
AFURLConnectionOperation
NSRecursiveLock
AFURLConnectionOperation在很多地方都使用到了遞迴鎖。例如:
//字串編碼格式 - (NSStringEncoding)responseStringEncoding { [self.lock lock]; if (!_responseStringEncoding && self.response) { NSStringEncoding stringEncoding = NSUTF8StringEncoding; if (self.response.textEncodingName) { CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName); if (IANAEncoding != kCFStringEncodingInvalidId) { stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding); } } self.responseStringEncoding = stringEncoding; } [self.lock unlock]; return _responseStringEncoding; }
NSRecursiveLock這種“遞迴鎖”,執行緒能夠多次持有該鎖,而不會出現“死鎖”現象。
OC中,還有其它形式的鎖,參考內容來自:
NSURLConnection與NSRunLoop
在- (void)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.runLoopModes為:
self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
首先,如果是直接呼叫NSURLConnection的initWithRequest:delegate:startImmediately:(第三個引數用YES,這個是designated
initializer)或者方法initWithRequest:delegate:時,NSURLConnection會預設執行在NSDefaultRunLoopMode模式下,即使再使用scheduleInRunLoop:forMode:設定執行模式也沒有用。如果NSURLConnection執行在NSDefaultRunLoopMode下,何為Run
Loop的模式Mode,請參考這篇Blog), 這篇Blog提到NSDefaultRunLoopMode是Run
Loop預設的執行模式,用於處理除了NSConnection物件的事件。
然而如果NSURLConnection是執行在NSDefaultRunLoopMode,而當前執行緒是主執行緒,並且UI上有類似滾動這樣的操作,那麼主執行緒的Run
Loop會執行在UITrackingRunLoopMode下,就無法響應NSURLConnnection的回撥。此時需要首先使用initWithRequest:delegate:startImmediately:(第三個引數為NO)生成NSURLConnection,再重新設定NSURLConnection的執行模式為NSRunLoopCommonModes,那麼UI操作和回撥的執行都將是非阻塞的,因為NSRunLoopCommonModes是一組run
loop mode的集合,預設情況下包含了NSDefaultRunLoopMode和UITrackingRunLoopMode。
AFHTTPRequestSerializer
AFHTTPRequestSerializer主要用來建立格式化請求引數,生成HTTP Header。
在其+ (instancetype)serializer類方法中,會設定Accept-Language、User-Agent等:
設定Accept-Language
NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
[[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
float q = 1.0f - (idx * 0.1f);
[acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
*stop = q <= 0.5f;
}];
[self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];
Accept-Language: zh-cn,zh;q=0.5
意思:瀏覽器支援的語言分別是中文和簡體中文,優先支援簡體中文。
詳解:Accept-Language表示瀏覽器所支援的語言型別;
zh-cn表示簡體中文;zh 表示中文;
q是權重係數,範圍 0 =< q <= 1,q 值越大,請求越傾向於獲得其“;”之前的型別表示的內容,若沒有指定 q
值,則預設為1,若被賦值為0,則用於提醒伺服器哪些是瀏覽器不接受的內容型別。
設定User-Agent
User-Agent是Http協議中的一部分,屬於頭域的組成部分,User Agent也簡稱UA。用較為普通的一點來說,是一種向訪問網站提供你所使用的瀏覽器型別、作業系統及版本、CPU 型別、瀏覽器渲染引擎、瀏覽器語言、瀏覽器外掛等資訊的標識。UA字串在每次瀏覽器 HTTP 請求時傳送到伺服器!