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ó
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
输出结果:
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;
}