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,一经查实,立即删除!

相关文章

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…

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;我们…

统计一行文本的单词个数_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解…

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

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

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

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

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&…

机器学习项目笔记

项目清单: 1. 商业目标2. 划定问题               监督或非监督&#xff0c;还是强化学习。3. 选择什么算法             回归还是分类&#xff0c; 数据量小可使用单机内存的 批量计算&#xff0c; 数据量大使用分布式的MapReduce 线上计算。4. 评估模型…

linux mysql主从配置

1准备两台服务器 一台是192.168.118.128 一台是192.168.118.129 2主服务器配置 192.168.118.128 修改my.cnf文件 server-id1 log-binmysql-bin #启动MySQL二进制日志系统&#xff0c; binlog-do-dbourneeddb #需要同步的数据库 binlog-ignore-dbmysql #不同步mysql系统数据库&…

svn新建仓库

1昨天需要在服务器上新建一个仓库&#xff0c;解决方法是把已有的仓库拷贝出来&#xff0c;库删除在放进去 2然后今天想看看有没有命令的方法 find / -name project 首先查看一下项目的位置 3创建仓库 svnadmin create /mnt/raid1/huge/project/test 4cd test Ls 5vi authz…

MySql数据库索引原理

写在前面&#xff1a;索引对查询的速度有着至关重要的影响&#xff0c;理解索引也是进行数据库性能调优的起点。考虑如下情况&#xff0c;假设数据库中一个表有10^6条记录&#xff0c;DBMS的页面大小为4K&#xff0c;并存储100条记录。如果没有索引&#xff0c;查询将对整个表进…

java实现坐标图进行拖拉拽放_js实现限定区域范围拖拉拽效果

本文实例为大家分享了js实现限定区域范围拖拉拽的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下需要在范围内拖拉拽&#xff0c;之前看来许多资料觉得都不是特别满足要求&#xff0c;今天自己写了一个&#xff0c;通过监听鼠标按下、鼠标抬起、鼠标移动事件来控制代…

mysql + keepalived高可用

1上次说过了mysql的主从配置 tar zxf keepalived-1.2.7.tar.gz cd keepalived-1.2.7 yum install gcc gcc-c yum install kernel-devel -y 2报错 configure: error: Popt libraries is required yum install popt-devel 3继续执行 ./configure --with-kernel-dir/usr/src/kerne…

java+向前进一_Java 线程基础

前言线程并发系列文章&#xff1a;熟练掌握线程原理与使用是程序员进阶的必经之路&#xff0c;网上很多关于Java线程的知识&#xff0c;比如多线程之间变量的可见性、操作的原子性&#xff0c;进而扩展出的Volatile、锁(CAS/Synchronized/Lock)、信号量等知识。有些文章只说笼统…

电子报账系统源码_网上商城系统建设心得,轻松搞定选择困难

当前&#xff0c;我们正处于一个互联网飞速发展的时代&#xff0c;特别是互联网电商的出现&#xff0c;给我们的生活带来了翻天覆地的变化&#xff0c;不出家门便可购买各种商品&#xff0c;不用再到处奔走寻找&#xff0c;通过网络便可快速下单&#xff0c;然后坐等送货上门。…

源码安装httpd

1 tar -xvf apr-1.7.0.tar.gz tar -xvf apr-util-1.6.1.tar.gz tar -xvf httpd-2.2.6.tar.gz 2cd apr-1.7.0 ./configure Make Make install 3cd apr-util-1.6.1 ./configure --with-apr/usr/local/apr 解决rpm -ivh libexpat-devel-2.2.4-alt1.i586.rpm tar -xvf expat-2.2…