1. 程式人生 > >iOS開源專案學習—— AFNetworking

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 請求時傳送到伺服器!