AFNetworking 3.0源码阅读 - AFURLResponseSerialization

 这次来说一下AFURLResponseSerialization这个HTTP响应类。

定义了一个协议,该协议返回序列化后的结果。后续的AFHTTPResponseSerializer以及他的子类都遵循了该协议

该类内有很多子类定义,这里借用一张图来展示,之后一个一个来说。

我们先来看下AFHTTPResponseSerializer在头文件中的定义有哪些。

可以看到有两个初始化方法,然后stringEncoding后面有一个宏,这个宏代表这弃用了。

 

 来看实现文件的部分。

这里有一个NSIndexSet。

NSIndexSet:代表一个不可变的独特的无符号整数的集合,称为索引,因为使用它们的方式。这个集合被称为索引集。你不应该使用索引集存储任意集合的整数值,因为索引集按索引排序范围的方式存储的。这使得它们更有效率比存储单个整数的集合。这也意味着每个索引值指数中只能出现一次。通俗点讲NSIndexSet就是一个唯一的,有序的,无符号整数的集合。

self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];

表示接受状态码范围200~299。

- (BOOL)validateResponse:(NSHTTPURLResponse *)responsedata:(NSData *)dataerror:(NSError * __autoreleasing *)error
{BOOL responseIsValid = YES;//默认为yesNSError *validationError = nil;//存在response且为NSHTTPURLResponse类if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {//条件:1.acceptableContentTypes存在 2.response的MIMEType不在范围内 3.MIMEType和data均不为空if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&!([response MIMEType] == nil && [data length] == 0)) {//data长度大于0且respone的URL存在if ([data length] > 0 && [response URL]) {//定义错误信息字典NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],NSURLErrorFailingURLErrorKey:[response URL],AFNetworkingOperationFailingURLResponseErrorKey: response,} mutableCopy];if (data) {//错误信息包含datamutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;}//生成NSerrorvalidationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);}responseIsValid = NO;}if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],NSURLErrorFailingURLErrorKey:[response URL],AFNetworkingOperationFailingURLResponseErrorKey: response,} mutableCopy];if (data) {mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;}validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);responseIsValid = NO;}}if (error && !responseIsValid) {*error = validationError;}return responseIsValid;
}

response有效性验证过程。

NSSecureCoding, NSCopying协议方法。

 

进入该属性类型NSJSONReadingOptions可以看到是下图这么定义的。

  • NSJSONReadingMutableContainers:返回是可变容器类型如NSMutableArray,NSMutableDictionay。

  • NSJSONReadingMutableLeaves:返回的字符串是NSMutableSting。

  • NSJSONReadingAllowFragments:json结构最外层可以不是NSArray和NSDictionay。

 

接着来看对应的实现文件部分。

三种初始化方法从init方法中可以看到acceptableContentTypes支持"application/json", "text/json", "text/javascript"三种。

- (id)responseObjectForResponse:(NSURLResponse *)responsedata:(NSData *)dataerror:(NSError *__autoreleasing *)error
{//response有效性无效if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {//无error或者code为NSURLErrorCannotDecodeContentData解析无效,要返回nilif (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {return nil;}}// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.// See https://github.com/rails/rails/issues/1742//data由空格字符构成也需要返回nilBOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];if (data.length == 0 || isSpace) {return nil;}NSError *serializationError = nil;id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];if (!responseObject){if (error) {*error = AFErrorWithUnderlyingError(serializationError, *error);}return nil;}if (self.removesKeysWithNullValues) {return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);}return responseObject;
}

转化和解析方法,这里又出现了两个定义的C函数贴在下面。

static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) {//error的domain和code与入参对影响等直接返回yesif ([error.domain isEqualToString:domain] && error.code == code) {return YES;} else if (error.userInfo[NSUnderlyingErrorKey]) {//否则判断userInfo中key为NSUnderlyingErrorKey是否有值,有递归调用自身return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain);}return NO;
}
static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) {//数组类if ([JSONObject isKindOfClass:[NSArray class]]) {//定义可变数组NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]];for (id value in (NSArray *)JSONObject) {
            [mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)];}return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray];} else if ([JSONObject isKindOfClass:[NSDictionary class]]) {//同上NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject];for (id <NSCopying> key in [(NSDictionary *)JSONObject allKeys]) {id value = (NSDictionary *)JSONObject[key];
//去除value为NSNull的key
if (!value || [value isEqual:[NSNull null]]) {[mutableDictionary removeObjectForKey:key];} else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions);}}return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary];}return JSONObject; } 

这里有点好奇为什么不把数组里面的NSNull对象也去掉而只是把字典中value为NSNull的key去掉。

NSSecureCoding, NSCopying协议方法。

 

解析XML的子类。

不多说比较好理解。

 

将JSON转换为PropertyList用到的子类。

ContentType支持application/x-plist。

 

这里是UIImage的一个分类,从方法名字上看可以想到是一个安全的NSData转Image的方法。

通过NSLock来解决多线程上的一些安全问题。

static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) {UIImage *image = [UIImage af_safeImageWithData:data];if (image.images) {return image;}return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
}static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) {if (!data || [data length] == 0) {return nil;}CGImageRef imageRef = NULL;CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);if ([response.MIMEType isEqualToString:@"image/png"]) {imageRef = CGImageCreateWithPNGDataProvider(dataProvider,  NULL, true, kCGRenderingIntentDefault);} else if ([response.MIMEType isEqualToString:@"image/jpeg"]) {imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);if (imageRef) {CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef);CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace);// CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so fall back to AFImageWithDataAtScaleif (imageColorSpaceModel == kCGColorSpaceModelCMYK) {CGImageRelease(imageRef);imageRef = NULL;}}}CGDataProviderRelease(dataProvider);UIImage *image = AFImageWithDataAtScale(data, scale);if (!imageRef) {if (image.images || !image) {return image;}imageRef = CGImageCreateCopy([image CGImage]);if (!imageRef) {return nil;}}size_t width = CGImageGetWidth(imageRef);size_t height = CGImageGetHeight(imageRef);size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);if (width * height > 1024 * 1024 || bitsPerComponent > 8) {CGImageRelease(imageRef);return image;}// CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreatesize_t bytesPerRow = 0;CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);if (colorSpaceModel == kCGColorSpaceModelRGB) {uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wassign-enum"if (alpha == kCGImageAlphaNone) {bitmapInfo &= ~kCGBitmapAlphaInfoMask;bitmapInfo |= kCGImageAlphaNoneSkipFirst;} else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {bitmapInfo &= ~kCGBitmapAlphaInfoMask;bitmapInfo |= kCGImageAlphaPremultipliedFirst;}
#pragma clang diagnostic pop}CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);CGColorSpaceRelease(colorSpace);if (!context) {CGImageRelease(imageRef);return image;}CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef);CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context);CGContextRelease(context);UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation];CGImageRelease(inflatedImageRef);CGImageRelease(imageRef);return inflatedImage;
}

上面的这些个方法涉及图形图像和CoreGraphics,不是很懂。。以后再补吧,先把代码贴在这里。

 

 

 

最后还有个AFCompoundResponseSerializer,也比较简单不常用不多说了。

 

通过该篇记录下之后需要学习的东西

  1. CoreGraphics
  2. NSError

 

转载于:https://www.cnblogs.com/kaisi/p/9442724.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/427153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3纵向输出字符串_Python 3.x 格式化输出字符串 % format 笔记

python格式化字符串有%和{}两种 字符串格式控制符.字符串输入数据格式类型(%格式操作符号)%%百分号标记%c字符及其ASCII码%s字符串%d有符号整数(十进制)%u无符号整数(十进制)%o无符号整数(八进制)%x无符号整数(十六进制)%X无符号整数(十六进制大写字符)%e浮点数字(科学计数法)%…

linux 下tomcat服务每天定时启动

1l先准备一个脚本 #!/bin/sh #./etc/profile export JAVA_HOME/usr/java/jdk1.6.0_45 sh /home/tomcat-bingchuang/bin/shutdown.sh sleep 60s sh /home/tomcat-bingchuang/bin/startup.sh 2放置到如上/home/ tomcat-bingchuang/bin/目录下 赋予777权限 并在linux里面设置…

Swordsman

ps&#xff1a;比赛的时候想到了做法&#xff0c;k次排序&#xff0c;然后每次消去能消的。。。然而这种做法是错误的&#xff0c;神奇的是测试案例中排在奇数的案例会WA&#xff0c;排在偶数的案例都过了&#xff0c;被注释的代码会T. #include<bits/stdc.h> #define UL…

java socket编程聊天室_Java Socket通信之聊天室功能

Java Socket通信之聊天室功能发布时间&#xff1a;2020-10-17 14:36:00来源&#xff1a;脚本之家阅读&#xff1a;73作者&#xff1a;LY_624本文实例为大家分享了Java Socket聊天室功能的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下Client.javaimport java.io.*;i…

python计算数组元素的和_python中数组的运算

Python中进行数组的运算需要调用NumPy包。其官网是&#xff1a;http://www.numpy.org/​www.numpy.orgNumPy是Python语言的一个扩充程序库。它支持高级大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。Numpy内部解除了CPython的GIL(全局解释器锁…

linux mysql数据库定时备份

1在linux上面创建一个文件夹&#xff0c;并且进行备份 cd /home mkdir backup cd backup 2创建一个脚本 Vi imaginebase.sh #!/bin/bash mysqldump -uroot -ppassword01! imaginebase > /home/backup/imaginebase_KaTeX parse error: Expected group after _ at position 1…

[NOI2014] 起床困难综合症

水题的题解也水...... 原题链接&#xff1a;洛谷 P2114 [NOI2014]起床困难综合症 位运算每一位之间互不干扰。 经过所有门之后每一位不外乎四种结果&#xff1a;一定是0&#xff0c;一定是1&#xff0c;不变或取反。 按位枚举&#xff0c;贪心即可。 对于不变的&#xff0c;我们…

java调用webroot下的文件_JAVA 访问WebRoot下的目录文件

/*** 获取到webroot里面的数据*/java.net.URL url2 classLoader.getResource("");String ROOT_CLASS_PATH url2.getPath() "/";File rootFile new File(ROOT_CLASS_PATH);String WEB_INFO_DIRECTORY_PATH rootFile.getParent() "/";File w…

统计一行文本的单词个数_word操作技巧:不同情况的文字统计方法

最近有朋友询问&#xff0c;如何快速统计出Word文档的字数&#xff1f;这个问题其实非常简单&#xff0c;但往往是这种最简单的知识容易被大家忽视&#xff0c;因此造成困扰。所以&#xff0c;今天我们将为大家详细介绍几种Word统计文档字数的方法&#xff0c;希望能帮助到你&a…

linux mysql5.6.27源码安装和错误解决

centos mysql5.6.27 1编译安装 先进入到文件放置的路径下 创建一个个文件 #mkdir–p /data/mysql/mysql #mkdir–p /data/mysql/mysqldat 2创建用户和用户组 groupadd mysql useradd -r -g mysql mysql 3赋予数据存放目录权限 chown mysql:mysql -R /data/mysql/mysqldata/ 4解…

java 接口数据类型_Java 数据类型(中): 抽象类与接口

抽象类和接口都是java对事物对象抽象的机制&#xff0c;是多态性的表现。在某些时候它们还可以互换&#xff0c;其实它们还是有区别的。1&#xff0c;抽象类(abstract class):对某些对象的抽象描述的类(对事物对象行为方法的声明&#xff0c;但是却不实现具体的方法内容&#x…

WebApi

WebAPI 和 MVC 的管道不同 1.Restful 架构风格和WebAPI 2.WebAPI 路由&特性路由 3.WebAPI 前后台调用 4.权限认证 5.跨域请求 6.WebAPI 依赖注入&面向切面 7.WebAPI 自动生成文档 .NETRemoting 速度很快 &#xff0c;平台要求&#xff0c; WebService 跨平台 &#x…

mysql集群和主从区别_搭建MySQL主从集群,主从复制过程中同步延迟问题

上一节我们成功搭建了主从复制、读写分离&#xff0c;实际上并发量和数据量不大的情况下&#xff0c;使用起来也是非常的流畅&#xff0c;无任何问题&#xff0c;可以正常运行了。但是&#xff0c;要保证高可用&#xff0c;高并发的情况&#xff0c;可以写数据库master就有累了…

MySQL之——The slave I/O thread stops because master and slave have equal...

1)操作系统 cat /etc/issue CentOS release 6.6 (Final) Kernel \r on an \m cat /proc/version Linux version 2.6.32-504.el6.x86_64 (mockbuildc6b9.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) ) #1 SMP Wed Oct 15 04:27:16 UTC 2014 …

数学:乘法逆元-拓展GCD

乘法逆元应用在组合数学取模问题中&#xff0c;这里给出的实现不见得好用 给出拓展GCD算法&#xff1a; 扩展欧几里得算法是指对于两个数a,b 一定能找到x,y&#xff08;均为整数&#xff0c;但不满足一定是正数&#xff09; 满足x*ay*bgcd(a,b) gcd&#xff08;x,y)是指x 与 y的…

java I O类大全_Java I/O最简单的几个类

今天把I/O中最简单的几个类整理了一下&#xff0c;之所以整理最简单的&#xff0c;是因为这样会让我更加快速方便的理顺这里面的东西&#xff0c;以前每一次用的时候都要先百度一下&#xff0c;觉得很烦。首先需要先看一下Read,Write和Stream&#xff0c;那么看下面的图就明确多…

rpm包安装mysql数据库

3.1上传以下两个rpm包到服务器上 MySQL-server-5.6.27-1.el6.x86_64.rpm MySQL-client-5.6.27-1.el6.x86_64.rpm 3.2卸载一个旧的mysql-libs包&#xff1a; rpm -e mysql-libs-5.1.73-3.el6_5.x86_64 --nodeps 3.3开始安装mysql-server服务器端 rpm -ivh MySQL-server-5.6.27…

micropython stm32f407 以太网_[MicroPython]STM32F407开发板DIY声光控开关

1.实验目的1. 学习在PC机系统中扩展简单I/O 接口的方法。2. 进一步学习编制数据输出程序的设计方法。3. 学习光敏模块的工作原理。4. 学习声音的工作原理。5. 学习F40 7Micropython开发板与声音传感器与光敏传感器的接线方法以及利用声音与光控制发光二极管亮灭。2.所需元器件F…

linux mysql数据库备份并删除前一分钟的数据

linux 中mysql数据库定时备份并删除前一分钟的所有数据 #!/bin/bash #mysqldump -uroot -ppassword01! imaginebase > /home/backup/imaginebase_KaTeX parse error: Expected EOF, got # at position 27: …%d_%H%M%S).sql #̲mysqldump -uroo…(date %Y%m%d_%H%M%S).sql.g…

打开 igv java_必备可视化Integrative Genomic Viewer(IGV)

你会用到的网站&#xff1a;写在前面&#xff1a;之前mac不小心升级了一下java&#xff0c;然后igv就不能用了&#xff0c;要写教程必须降级java首先&#xff0c;看官方说明&#xff0c;需要安装Java -8&#xff0c;9以上版本不支持。我的mac不知道什么时候更新到了java 10&…