AFNetworking3.1.0源碼分析(四)詳解AFHTTPRequestSerializer 之初始化方法

1:類圖介紹

在AFHTTPSessionManager 初始化方法中可以看到 AFNetworking 默認使用的網絡請求序列化類是AFHTTPRequestSerializer,一下是關於它的類圖:


2:類功能分析:

 一:初始化函數:

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    ①
    
    self.stringEncoding = NSUTF8StringEncoding;

    ②

    self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
    self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
    // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
    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"];

    ③

    NSString *userAgent = nil;
#if TARGET_OS_IOS
    // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
    userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)☺", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
#elif TARGET_OS_WATCH
    // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
    userAgent = [NSString stringWithFormat:@"%@/%@ (%@; watchOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[WKInterfaceDevice currentDevice] model], [[WKInterfaceDevice currentDevice] systemVersion], [[WKInterfaceDevice currentDevice] screenScale]];
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
    userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
#endif
    
    if (userAgent) {

        
        if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
            NSMutableString *mutableUserAgent = [userAgent mutableCopy];
            if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
                userAgent = mutableUserAgent;
            }
        }
        [self setValue:userAgent forHTTPHeaderField:@"User-Agent"];
    }

    ④

    // HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
    self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];

    ⑤

    self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }
    return self;
}


①:設置默認的編碼格式是utf8

②:根據系統的語言設置http請求頭字段Accept-Language 的值,eg(zh-CN;q=0.8) 解釋後面的q表示前面語言的權值,如果是多種語言,服務器可以根據圈值的大小優先響應哪種請求。具體含義可參見文章

③:這個步驟的操作意思是刪除user-agent 中所有的不能ascii編碼的字符,詳細的函數介紹:

CFStringTransform(CFMutableStringRef string, CFRange *range, CFStringRef transform, Boolean reverse)對於此函數的詳細介紹可參考文章,下面我將使用實例介紹此函數的威力,拿AFNetworking中使用舉例。

   1:將中文變成漢語拼音帶音調代碼如下:

NSString *userAgent = @"中華人民共和國";
    NSMutableString *mutableUserAgent = [userAgent mutableCopy];
    CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin", false);
    NSLog(@"%@",mutableUserAgent);
輸出結果:

2016-12-06 21:06:38.925 test2[15785:400567] zhōng huá rén mín gòng hé guó


2:將中文變成漢語拼音不帶音調代碼如下:

 NSString *userAgent = @"中華人民共和國";
    NSMutableString *mutableUserAgent = [userAgent mutableCopy];
    CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII", false);
    NSLog(@"%@",mutableUserAgent);
    NSLog(@"%@",userAgent);
輸出結果:

2016-12-06 21:09:41.519 test2[15858:404061] zhong hua ren min gong he guo


3:移除所有非ASCII(0-255包含擴展字符)值範圍的所有字符代碼如下:


輸出結果:

2016-12-06 21:12:38.127 test2[15936:407291] 1Aa3
解釋爲什麼會有3,先參考文章獲取包含中英文表情混合字符中的每個字符裏面同時對每個字符的unicode值進計算,計算之後3的值(153,這個字符3是在mac上使用搜狗輸入法輸入)是在ASCII(0-255包含擴展字符)範圍之內。

4:AFNetworking的使用解釋:

CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)
輸出的效果是以上3點的結合(層層過濾):
2016-12-06 21:44:40.206 test2[16642:436125] 1Aa a3zhong hua ren min gong he guo


④:http請求方法中 GET HEAD DELETE 此三種方法是對參數直接放在URI中,因此需要設置,對這幾種方式請求的參數編碼

⑤:主要是對系統的函數的監聽(KVO)系統的函數如下代碼(_AFHTTPRequestSerializerObservedKeyPaths):

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章