深入iOS开源项目:原生网络请求与AFNetworking 3.1实践指南

更新:11-09 名人轶事 我要投稿 纠错 投诉

大家好,关于深入iOS开源项目:原生网络请求与AFNetworking 3.1实践指南很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!

NSURLConnection.sendAsynchronousRequest(URLRequest(url: URL(string: "http://rap2api.taobao.org/app/mock/117041/mock")!),queue: OperationQueue.main) { (resp, data, error) in

打印(分别)

}已废弃,不再介绍。

NSURLSession 和 NSURLConnection 的区别

1.下载方法

NSURLConnection下载文件时,首先将整个文件下载到内存,然后写入沙箱。如果文件比较大,内存就会暴涨。

当你使用NSURLSessionDownloadTask下载文件时,默认会下载到沙箱中的tem文件中,不会出现内存激增的情况。但下载完成后tem中的临时文件将会被删除。初始化任务方法时需要回调completionHandler。添加代码以保存文件。

2、控制方法

NSURLConnection 实例化该对象。实例化开始时,发送默认请求(同步发送),无需调用start方法。取消可以停止发送请求。停止后无法继续访问,需要创建新的请求。

NSURLSession有三种控制方法,cancel(取消)、pause(挂起)、Continue(恢复)。暂停后,可以通过继续来恢复当前请求任务。

3. 配置

NSURLSession构造函数中有一个NSURLSessionConfiguration类参数(sessionWithConfiguration:delegate:delegateQueue)可以设置配置信息,该参数决定cookie、安全和缓存策略、最大主机连接数、资源管理、网络超时等配置。

NSURLConnection 无法执行此配置。 NSURLConnection 依赖于一个全局配置对象

2、NSURLSession 了解

相关类关系图

img

NSURLSession

1.sharedSession

全局共享单例会话

2. + sessionWithConfiguration:delegate:delegateQueue:

自定义会话: 自定义配置文件,设置代理,我们大部分时间都用这个

3. NSURLSessionConfiguration *config=[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"xxx"];

_backgroundSession=[NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

后台会话:也是一种自定义会话,但它专门用于后台上传/下载任务。

哪种类型的会话完全由其内部配置决定。

NSURLSessionConfiguration

1.默认会话配置

系统默认

2. 临时会话配置

只有内存缓存,没有磁盘缓存配置

3. 后台会话配置

这里需要指定一个标识符,用于后台重新连接session对象(这是后台上传/下载的配置)

我们还可以为Configuration对象自定义一些属性,比如每个端口最大并发HTTP请求数、是否允许蜂窝网络、请求缓存策略、请求超时、cookie/证书存储策略等。

NSURLSessionDelegate

imgNSURLSessionDelegate :会话级代理方法

NSURLSessionTaskDelegate : 所有任务级代理方法

NSURLSessionDataDelegate : 数据和上传的任务级代理方法

NSURLSessionDownloadDelegate : 任务级面向下载的代理方法

NSURLSessionStreamDelegate : 任务级面向流的代理方法

一旦指定了会话代理,会话就会对代理产生强引用。如果不主动取消会话,就会发生内存泄漏!

强势报价的原因:

下载任务、网络任务均为异步操作

NSURLSessionTask

imgNSURLSessionTask : Task 的抽象基类

NSURLSessionDataTask : 以NSData 的形式接收URLRequest 的内容

NSURLSessionUploadTask : 上传本地磁盘上的NSData 或文件。完成后,收到NSData 形式的URLRequest 响应。

NSURLSessionDownloadTask : 返回下载完成后本地磁盘上临时文件的URL路径。

NSURLSessionStreamTask :用于建立TCP/IP连接

NSURLSessionTaskMetrics 和 NSURLSessionTaskTransactionMetrics

。发送请求/DNS查询/TLS握手/请求响应等各种链路的时间指标统计。我们可以更轻松地检测、分析应用程序缓慢请求发生的位置,并对其进行优化以提高应用程序的性能。

NSURLSessionTaskMetrics 对象与NSURLSessionTask 对象一一对应。每个NSURLSessionTaskMetrics 对象有3 个属性:

taskInterval : 任务从开始到结束所花费的总时间redirectCount : 任务重定向次数transactionMetrics : 任务派生的每个子请求从发出请求到接收数据。它是一个包含很多NSURLSessionTaskTransactionMetrics 对象的数组,每个对象都代表下图中的一个子流程。 imgAPI 很简单,只是一个方法: - (void)URLSession:task:didFinishCollectingMetrics:当收集完成时会调用该方法。

身份验证和自定义TLS

当服务器请求身份验证或TLS 握手期间需要证书时,URLSession 将调用其代理方法URLSession:didReceiveChallenge:completionHandler: 来处理。

如果不实现代理方法,URLSession将会这样做:

- 使用身份验证信息作为请求URL 的一部分(如果可用)

- 在用户的钥匙串(在macOS 中)和应用程序的钥匙串(在iOS 中)中查找网络密码和证书。如果证书仍然不可用或服务器拒绝它,则连接将继续未经身份验证。

- 对于HTTP(S)连接,请求失败并返回状态码,并且可能提供一些替代内容,例如私人网站的公共页面。

- 对于其他URL类型(如FTP等),连接请求失败,直接返回错误信息

App Transport Security

。 iOS9开始支持ATS,默认情况下ATS只支持发送HTTPS请求,不允许发送不安全的HTTP请求。如果用户需要发送HTTP请求,则需要在info.plist中配置NSAppTransportSecurityNSAllowsArbitraryLoads

NSURLSession 工作流程

NSURLSession 发起一个网络请求

//设置配置

NSURLSessionConfiguration *config=[NSURLSessionConfiguration defaultSessionConfiguration];

/** 设置其他配置属性**/

//代理队列

NSOperationQueue *queue=[NSOperationQueue mainQueue];

//创建会话

NSURLSession *session=[NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:queue];

//使用session创建n个任务

NSURLSessionDownloadTask *task=[会话downloadTaskWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];

//开始

[任务简历];

身份验证或者 TLS握手

这是所有任务都必须经历的一个过程。当服务器请求身份验证或在TLS 握手期间需要提供证书时,URLSession 将调用其代理方法URLSession:didReceiveChallenge:completionHandler: 来处理。另外,如果连接过程中收到服务器需要身份验证的响应时,也会调用代理方法。

重定位response

这也是所有任务都可能经历的一个过程。如果响应是HTTP 重定位,则会话将调用代理。

URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler: 方法

这里需要调用completionHandler告诉session是否允许重定位,或者重定向到另一个URL,或者传递nil来表示重定位响应体有效并返回。

如果代理没有实现此方法,则允许重定位,直到达到最大重定位数。

DataTask

1. 对于数据任务,会话会调用代理的URLSession:dataTask:didReceiveResponse:completionHandler: 方法来决定是否将数据任务转换为下载任务,然后调用完成回调继续接收数据或下载数据。

如果您的应用选择转换为下载任务,会话将调用代理的URLSession:dataTask:didBecomeDownloadTask: 方法,并将新的下载任务对象作为方法参数传递给您。之后,代理将不再接收来自数据任务的回调,而是接收来自下载任务的回调。

2. 服务器向客户端传输数据时,代理会定期收到URLSession:dataTask:didReceiveData: 回调。如果需要使用数据,可以通过代码来存储。

3. 会话将调用URLSession:dataTask:willCacheResponse:completionHandler: 询问您的应用是否允许缓存。如果代理没有实现该方法,则默认使用会话绑定的Configuration的缓存策略。

DownloadTask

1. 对于通过downloadTaskWithResumeData: 创建的下载任务,会话将调用代理的URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes: 方法。

2、服务器向客户端传输数据时,调用URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:向用户传输数据

- 当用户暂停下载时,调用cancelByProducingResumeData:将下载的数据传递给用户。

- 如果用户想继续下载,将刚才的resumeData作为参数传递给downloadTaskWithResumeData:方法,创建一个新的任务继续下载。

3. 如果下载任务成功完成,请调用URLSession:downloadTask:didFinishDownloadingToURL: 为您提供临时文件的URL 路径。这时,你应该在代理方法返回之前读取它的数据或者持久化该文件。

UploadTask

向服务器上传数据时,代理会定期接收

URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:

回电并获取上传进度报告。

StreamTask

如果任务数据是从流发送的,会话将调用代理的URLSession:task:needNewBodyStream: 方法来获取NSInputStream 对象并提供新请求的正文数据。

Task completion

当任何任务完成时,将调用URLSession:task:didCompleteWithError: 方法。错误可能是nil(请求成功),而不是nil(请求失败)

- 请求失败,但任务可恢复,则错误对象的userInfo字典中有一个与NSURLSessionDownloadTaskResumeData对应的值。您应该将此值传递给downloadTaskWithResumeData: 方法以恢复下载。

- 请求失败,但任务无法恢复下载,则应重新创建下载任务并从头开始下载

- 由于其他原因(例如服务器错误等)创建和恢复请求

注意:NSURLSession不会接收来自服务器的错误,代理只会接收来自客户端的错误,例如无法解析主机名或无法连接到主机等。客户端错误在URL加载系统错误中定义代码。服务器端错误通过HTTP状态方法传输。有关详细信息,请参阅NSHTTPURLResponse 和NSURLResponse 类

销毁session

。如果您不再需要会话,请务必调用其invalidateAndCancel 或finishTasksAndInvalidate 方法。 (前者是取消所有未完成的任务然后使会话失效,后者是等待当前正在执行的任务完成后再使会话失效)。否则,可能会发生内存泄漏。

另外,session过期后,会调用URLSession:didBecomeInvalidWithError:方法,然后session会释放对代理的强引用。

Background Transport

需要注意的是,在后台会话中,某些代理方法将无效。下面是使用后台会话:时的一些注意事项

后台会话必须提供代理来处理紧急情况,并且仅支持HTTP(S)协议。其他协议不可用。仅支持上传/下载任务,不支持数据任务。当任务数量达到系统规定的临界值时,后台任务的数量就会受到限制。一些后台任务将被取消。换句话说,一个上传/下载时间较长的任务很可能会被系统取消,过一段时间后又重新启动,所以支持断点续传很重要。如果应用在后台时启动了一个后台传输任务,那么这个任务很可能出于性能考虑随时被系统取消(相当于session的Configuration对象的discretionary属性为true)。确实有很多后台会话限制。所以尽量使用前端session来做事情。

注意:

后台会话最适合传输支持断点恢复的大文件。或者对这个流程进行一些有针对性的优化。

- 上传/下载前最好将文件压缩成zip/tar等压缩文件。

- 根据数据段分别发送大文件。发送后,服务器会将数据拼接在一起。

- 上传时,服务器应返回一个标识符,以便跟踪传输状态并及时进行传输调整。

- 添加一个web代理服务器中间层,方便上面的优化

如何使用

那么这个后台传输怎么用呢?

创建后台会话

NSURLSessionConfiguration *config=[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"xxxx"];//identifier用于后台重新连接session对象(这是后台上传/下载的config)

_backgroundSession=[NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];创建上传或下载任务

NSURL *URL=[NSURL URLWithString:@"http://www.bz55.com/uploads/allimg/140402/137-140402153504.jpg"];

NSURLRequest *请求=[NSURLRequest requestWithURL:URL];

self.task=[self.session downloadTaskWithRequest:request];

注意: 无法使用带有completionHandler的方法创建后台任务

Note : 如果任务只需要在应用进入后台后处理,则无法调用【任务恢复】主动执行。程序进入后台后会自动执行。我们等待下载一半进入后台,打开App Switcher,过一会儿你就会发现,图片下载完成后,就会显示在应用程序上。方法调用顺序为:以下四个方法都是在app处于后台时调用。

img2017-03-24 14:17:09.458415 JRBgSessionDemo[2766:1080861] 下载- 58%

2017-03-24 14:17:09.567957 JRBgSessionDemo[2766:1080861] 下载- 59%

2017-03-24 14:17:16.916830 JRBgSessionDemo[2766:1080828] -[AppDelegate application:handleEventsForBackgroundURLSession:completionHandler:]

2017-03-24 14:17:16.951185 JRBgSessionDemo[2766:1080977] -[DownloadViewController URLSession:downloadTask:didFinishDownloadingToURL:]

2017-03-24 14:17:16.953951 JRBgSessionDemo[2766:1080977] -[DownloadViewController URLSession:task:didCompleteWithError:]

2017-03-24 14:17:16.954574 JRBgSessionDemo[2766:1080977] -[DownloadViewController URLSessionDidFinishEventsForBackgroundURLSession:]

总结后台传输

尝试使用真机进行调试,模拟器会跳过一两个方法,只能执行上传/下载任务,但无法执行数据任务。无法使用带宽。 completionHandler方法创建一个任务,否则程序会直接挂掉。 Applecation 中的completionHandler 必须被存储,然后在处理完所有内容后调用,以告诉系统您可以拍摄快照并挂起应用程序。后台下载最好支持断点续传,因为任务可能会被系统主动取消(例如系统性能下降、资源不足时) 6、后台任务可以通过通知、VoIP 唤醒等方式唤醒。

其他重要知识

1、线程安全

URLSession API 都是线程安全的。您可以在任何线程上创建会话和任务,任务将自动安排在适当的代理队列中运行。

其他线程中可能会调用后台传输的代理方法URLSessionDidFinishEventsForBackgroundURLSession:

在此方法中,您应该返回主线程并调用完成处理程序以触发AppDelegate 中的application:handleEventsForBackgroundURLSession:completionHandler: 方法。

2、NSCopying Behavior

会话、任务和配置对象均支持复制操作:

- 会话/任务副本: 返回对象本身

- 配置副本: 返回一个不可变对象。

3、completionHandler

如果实现了URLSession:didReceiveChallenge:completionHandler: 等带有completionHandler的方法,并且在该方法中没有调用completionHandler,请求会被阻塞

4、断点续传

下载失败/暂停/被取消,可以通过任务的-cancelByProducingResumeData: 方法保存下载的数据,然后调用会话的downloadTaskWithResumeData: 方法,该方法会触发代理的URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes: 方法。这部分知识来自于互联网。源码站点,Demo下载

AFNetworking v3.1.0

从需求出发一一分析AFNetworking v3.1.0

AFNetworking的类结构图

img

1、基本使用与实现原理

AFURLSessionManager

1.继承自NSObject,以组合方式包装NSURLSession

2.提供工厂,但不是单例,根据NSURLSessionConfiguration初始化

3、多线程使用NSOperationQueue,默认最大并发数为1。

4.默认JSON类型响应序列化

5.提供数据、上传、下载三种服务

AFHTTPSessionManager

1.继承自AFURLSessionManager,专门用于实现HTTPS协议,提供POST、GET、HEAD、DELETE、PUT、PATCH等便捷方法。具体实现直接或间接调用父类AFURLSessionManager的数据业务方法,不涉及下载和上传业务。

2、在父类AFURLSessionManager的基础上,隐藏了NSURLRequest的概念,简化为urlString,是相对于baseURL的相对路径,内部会进行拼接,形成完整的urlSt

ring。 3、直接根据url初始化 AFHTTPSessionManager,提供工厂,但是不是单例

通过 AFURLSessionManager 实现一个请求

///////数据//////// - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE; ////////上传/////// - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler; ///////下载//////// - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

通过 AFHTTPSessionManager 实现一个请求

- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(nullable id)parameters success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;请求知道如何构建了,我们看一看底层具体的实现原理

请求的底层原理

AFNetworking的操作都是基于NSURLSession 我们具体分析整个逻辑上的细节: AF中声明了几个静态的C语言函数 url_session_manager_creation_queue: 单例 串行队列 专用于构建操作 url_session_manager_create_task_safely:用上面构建的队列顺序构建task url_session_manager_processing_queue:单例 并行队列 专用于 任务响应解析 url_session_manager_completion_group:单例 队列组1、AFURLSessionManager的构建1、根据 NSURLSessionConfiguration 初始化 2、配置线程队列 NSOperationQueue,默认最大并发数为 1 3、NSURLSessionConfiguration 和 队列 构建 NSURLSession,@synchronized 锁 4、配置响应序列化,默认JSON类型 5、配置安全策略 6、锁 NSLock2、AFHTTPSessionManager的构建继承自AFURLSessionManager 直接根据url初始化 AFHTTPSessionManager,提供工厂,但是不是单例 初始化 initWithBaseURL:sessionConfiguration: 初始化 requestSerializer 为 AFHTTPRequestSerializer 用来构建 NSMutableURLRequest 初始化 responseSerializer 为 AFJSONResponseSerializer3、NSMutableURLRequest构建(如果是通过AFHTTPSessionManager 构建请求)URL拼接,参数配置,请求头配置等操作4、NSURLSessionDataTask的构建1、构建task的时候会使用 url_session_manager_create_task_safely 来保证安全构建任务 2、AFURLSessionManagerTaskDelegate 代理初始化 代理通过manager 弱持有sessionManager 代理完成 上传、下载的 NSProgress设置 NSProgress 取消、挂起、运行 关联task 的block设置 (weak持有 task) NSProgress fractionCompleted(某个任务已完成单元量占总单元量的比例) 监听设置 3、mutableTaskDelegatesKeyedByTaskIdentifier 添加代理键值对 (有锁) 通过全局字典保存任务代理,task.taskIdentifier 为 key, AFURLSessionManagerTaskDelegate 代理 为 value 4、Task通知监听添加,监听 taskDidResume 和 taskDidSuspend (有锁)5、NSURLSessionTask执行AFURLSessionManagerTaskDelegate 处理网络请求回调 SessionManager实现了 NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate 请求结果的回调会在 SessionManager 中处理 SessionManager定义的回调block也在这处理 AFURLSessionManagerTaskDelegate 的对响应结果部分的处理也通过 SessionManager 进行代理转发6、AFURLSessionManager清理NSURLSessionDataTask请求结束后进行清理,清理操作都有加锁 removeDelegateForTask removeNotificationObserverForTask 移除通知 mutableTaskDelegatesKeyedByTaskIdentifier 移除代理键值对

2、任务进度设置和通知监听、代理转发等请求扩展需求

上面提到的NSURLSessionDataTask执行后会回调回SessionManager

Session 层次的回调

NSURLSessionTaskDelegate 协议回调1、URLSession:didBecomeInvalidWithError: 无效请求 回调block: sessionDidBecomeInvalid 发出通知 2、URLSession:didReceiveChallenge:completionHandler: 回调block: sessionDidReceiveAuthenticationChallenge 否则 根据是否需要 和 securityPolicy 配置 决定 NSURLSessionAuthChallengeDisposition 和 NSURLCredential 3、URLSessionDidFinishEventsForBackgroundURLSession: 回调block: didFinishEventsForBackgroundURLSession 在iOS中使用NSURLSession,当一个下载任务完成时,app将会自动重启。app代理方法application:handleEventsForBackgroundURLSession:completionHandler:负责重建合适的会话,存储完成处理块,并在会话对象调用会话代理的 URLSessionDidFinishEventsForBackgroundURLSession:方法时调用完成处理块。

Task 层次的回调

NSURLSessionTaskDelegate 协议回调1、URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler HTTP 重定向 回调block: taskWillPerformHTTPRedirection AF重写的 respondsToSelector 中拦截了 willPerformHTTPRedirection 这个 selector,当 taskWillPerformHTTPRedirection存在时才执行。 2、URLSession:task:didReceiveChallenge:completionHandler: Task 任务层次的授权、证书问题

回调block:sessionDidReceiveAuthenticationChallenge 否则 根据是否需要 和 securityPolicy 配置 决定 NSURLSessionAuthChallengeDisposition 和 NSURLCredential 3、URLSession:task:needNewBodyStream: 回调block: taskNeedNewBodyStream 如果app使用流作为请求体,还必须提供一个自定义会话代理实现 当以流的形式上传,认证失败,任务将不再在重要该流进行上传。通过这个方法获取新的NSInputStream 4、URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: 代理: AFURLSessionManagerTaskDelegate 通过这个方法来获取上传进度信息 回调block: taskDidSendBodyData 5、URLSession:task:didCompleteWithError: 代理: AFURLSessionManagerTaskDelegate 响应解析 回调block: taskDidComplete 任务结束,成功或者失败都会调用,执行通知的移除、mutableTaskDelegatesKeyedByTaskIdentifier 的 代理键值对移除 6、URLSession:task:didFinishCollectingMetrics 指标统计 代理: AFURLSessionManagerTaskDelegate 回调block: taskDidFinishCollectingMetricsNSURLSessionDataDelegate 协议回调1、URLSession:dataTask:didReceiveResponse:completionHandler 接受响应 回调block: dataTaskDidReceiveResponse 2、URLSession:dataTask:didBecomeDownloadTask 代理: 删除原有任务对应的代理、通知、mutableTaskDelegatesKeyedByTaskIdentifier键值对,重新添加新的下载任务 3、URLSession:dataTask:didReceiveData 代理: 转发至 AFURLSessionManagerTaskDelegate 统计下载进度 回调block: dataTaskDidReceiveData 4、URLSession:dataTask:willCacheResponse:completionHandler 回调block: dataTaskWillCacheResponse 询问你的app是否允许缓存. 如果代理不实现这个方法的话, 默认使用session绑定的Configuration的缓存策略. 5、URLSessionDidFinishEventsForBackgroundURLSession 回调block: didFinishEventsForBackgroundURLSessionNSURLSessionDownloadDelegate 协议 回调1、URLSession:downloadTask:didFinishDownloadingToURL: 提供app下载内容的临时存储目录 代理: AFURLSessionManagerTaskDelegate 回调block: downloadTaskDidFinishDownloading 2、URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite 提供了下载进度的状态信息 代理: AFURLSessionManagerTaskDelegate 统计进度 回调block: downloadTaskDidWriteData 3、URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes 告诉app尝试恢复之前失败的下载 代理: AFURLSessionManagerTaskDelegate 统计进度 回调block: downloadTaskDidResume

3、请求参数的序列化

相关类

AFURLRequestSerialization 协议AFHTTPRequestSerializer 继承自NSObject 实现 AFURLRequestSerialization 协议AFJSONRequestSerializer 继承自 AFHTTPRequestSerializerAFPropertyListRequestSerializer 继承自 AFHTTPRequestSerializerAFMultipartFormData 协议AFHTTPRequestSerializer AFJSONRequestSerializer AFPropertyListRequestSerializer 都实现了 AFURLRequestSerialization 都实现了序列化请求的方法: - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error 方法主要做了: 1、从自己的head里去遍历,如果有值则设置给request的head 2、把各种类型的参数,array dic set转化成字符串,给request 3、最后判断该request中是否包含了GET、HEAD、DELETE,都包含在HTTPMethodsEncodingParametersInURI)。 因为这几个method的quey是拼接到url后面的。 而POST、PUT是把query拼接到http body中的。 实现该方法 请求序列化器可以将参数编码为查询字符串,HTTP主体,根据需要设置适当的HTTP头字段。 例如,JSON请求序列化器可以将请求的HTTP主体设置为JSON表示,并将Content-Type HTTP标头字段值设置为application / json。

特殊属性

AFHTTPRequestSerializer1、mutableObservedChangedKeyPaths 来源自 AFHTTPRequestSerializerObservedKeyPaths(),存了一些系统定义的请求头部键值对信息 2、mutableHTTPRequestHeaders 自定义的部分请求头部键值对信息 3、requestHeaderModificationQueue dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT); 并发操作队列,用于请求变更的操作,mutableHTTPRequestHeaders的修改 4、- (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters error:(NSError *__autoreleasing *)error 方法做了几个事情: 1、设置request的请求类型,GET、POST等 2、往request里添加一些默认参数设置 3、把需要传递的参数进行编码,并且设置到request中去,主要就是调用 AFURLRequestSerialization 协议中的 requestBySerializingRequest 方法AFJSONRequestSerializer主要是 [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; content-Type的不同AFPropertyListRequestSerializer[mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];AFMultipartFormDataAFMultipartFormData是一份协议,用于拼装 formdata

4、响应数据的解析

相关类

@protocol AFURLResponseSerialization@interface AFHTTPResponseSerializer : NSObject@interface AFJSONResponseSerializer : AFHTTPResponseSerializer @interface AFXMLParserResponseSerializer : AFHTTPResponseSerializer @interface AFXMLDocumentResponseSerializer : AFHTTPResponseSerializer @interface AFPropertyListResponseSerializer : AFHTTPResponseSerializer @interface AFImageResponseSerializer : AFHTTPResponseSerializer @interface AFCompoundResponseSerializer : AFHTTPResponseSerializer 不同类型的解析器AFNetworking的多数类都支持序列化,但实现的是NSSecureCoding的接口,而不是NSCoding,区别在于解数据时要指定Class,用-decodeObjectOfClass:forKey:方法代替了-decodeObjectForKey:。这样做更安全,因为序列化后的数据有可能被篡改,若不指定Class,-decode出来的对象可能不是原来的对象,有潜在风险。

5、额外的功能

AFSecurityPolicy

HTTPS连接建立过程大致是,客户端和服务端建立一个连接,服务端返回一个证书,客户端里存有各个受信任的证书机构根证书(CA根证书),用这些根证书对服务端返回的证书进行验证,经验证如果证书是可信任的,就生成一个pre-master secret,用这个证书的公钥加密后发送给服务端,服务端用私钥解密后得到pre-master secret,再根据某种算法生成master secret,客户端也同样根据这种算法从pre-master secret 生成 master secret,随后双方的通信都用这个 master secret 对传输数据进行加密解密。1、证书是怎样验证的?怎样保证中间人不能伪造证书?建立https连接时,服务端返回证书A给客户端,客户端的系统里的CA机构根证书有这个CA机构的公钥,用这个公钥对证书A的加密内容F1解密得到F2,跟证书A里内容F对比,若相等就通过验证。 整个流程大致是:F->CA私钥加密->F1->客户端CA公钥解密->F。因为中间人不会有CA机构的私钥,客户端无法通过CA公钥解密,所以伪造的证书肯定无法通过验证。2、什么是 SSL Pinning可以理解为证书绑定,用来验证服务器就是我要的服务器。 是指客户端直接保存服务端的证书,建立https连接时直接对比服务端返回的和客户端保存的两个证书是否一样,一样就表明证书是真的,不再去系统的信任证书机构里寻找验证。这适用于非浏览器应用,因为浏览器跟很多未知服务端打交道,无法把每个服务端的证书都保存到本地,但CS架构的像手机APP事先已经知道要进行通信的服务端,可以直接在客户端保存这个服务端的证书用于校验。 为什么直接对比就能保证证书没问题?如果中间人从客户端取出证书,再伪装成服务端跟其他客户端通信,它发送给客户端的这个证书不就能通过验证吗?确实可以通过验证,但后续的流程走不下去,因为下一步客户端会用证书里的公钥加密,中间人没有这个证书的私钥就解不出内容,也就截获不到数据,这个证书的私钥只有真正的服务端有,中间人伪造证书主要伪造的是公钥。 为什么要用SSL Pinning?正常的验证方式不够吗?如果服务端的证书是从受信任的的CA机构颁发的,验证是没问题的,但CA机构颁发证书比较昂贵,小企业或个人用户可能会选择自己颁发证书,这样就无法通过系统受信任的CA机构列表验证这个证书的真伪了,所以需要SSL Pinning这样的方式去验证。AFSecurityPolicy分三种验证模式AFSSLPinningModeNone 这个模式表示不做SSL pinning,只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过,若是自己服务器生成的证书,这里是不会通过的。 AFSSLPinningModePublicKey 这个模式同样是用证书绑定方式验证,客户端要有服务端的证书拷贝,只是验证时只验证证书里的公钥,不验证证书的有效期等信息。只要公钥是正确的,就能保证通信不会被窃听,因为中间人没有私钥,无法解开通过公钥加密的数据。 AFSSLPinningModeCertificate 这个模式表示用证书绑定方式验证证书,需要客户端保存有服务端的证书拷贝,这里验证分两步,第一步验证证书的域名/有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。 除了公钥外,其他能容也要一致才能通过验证。AFSecurityPolicy属性分析1、pinnedCertificates 这个属性保存着所有的可用做校验的证书的集合。AFNetworking 默认会搜索工程中所有 .cer的证书文件。如果想制定某些证书,可使用certificatesInBundle在目标路径下加载证书,然后调用policyWithPinningMode:withPinnedCertificates创建一个本类对象。 注意: 只要在证书集合中任何一个校验通过,evaluateServerTrust:forDomain: 就会返回true,即通过校验。 2、allowInvalidCertificates 使用允许无效或过期的证书,默认是不允许。 3、validatesDomainName 是否验证证书中的域名domainAFSecurityPolicy方法分析1、默认的实例对象,默认的认证设置为: 不允许无效或过期的证书 验证domain名称 不对证书和公钥进行验证 2、certificatesInBundle:(NSBundle *)bundle 返回指定bundle中的证书。如果使用AFNetworking的证书验证 ,就必须实现此方法,并且使用policyWithPinningMode:withPinnedCertificates 方法来创建实例对象。 3、evaluateServerTrust:forDomain: 评估服务器是否需要证书验证 在二进制的文件中获取公钥的过程是这样 ① NSData *certificate ->CFDataRef ->(SecCertificateCreateWithData) ->SecCertificateRef allowedCertificate ②判断SecCertificateRef allowedCertificate 是不是空,如果为空,直接跳转到后边的代码 ③allowedCertificate 保存在allowedCertificates数组中 ④allowedCertificates ->(CFArrayCreate) ->SecCertificateRef allowedCertificates[1] ⑤根据函数SecPolicyCreateBasicX509() ->SecPolicyRef policy ⑥SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust) ->生成SecTrustRef allowedTrust ⑦SecTrustEvaluate(allowedTrust, &result) 校验证书 ⑧(__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust) ->得到公钥id allowedPublicKey

AFNetworkReachabilityManager

网络检测// 如果要检测网络状态的变化,必须用检测管理器的单例的startMonitoring [[AFNetworkReachabilityManager sharedManager] startMonitoring]; // 检测网络连接的单例,网络变化时的回调方法 [[AFNetworkReachabilityManager sharedManager]setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { NSLog(@"%ld",(long)status); switch (status) { case AFNetworkReachabilityStatusUnknown: NSLog(@"网络错误"); break; case AFNetworkReachabilityStatusNotReachable: NSLog(@"没有连接网络"); break; case AFNetworkReachabilityStatusReachableViaWWAN: NSLog(@"蜂窝网络"); break; case AFNetworkReachabilityStatusReachableViaWiFi: NSLog(@"wifi"); break; } }]; /* AFNetworkReachabilityStatusUnknown = -1, //未知、网络错误 AFNetworkReachabilityStatusNotReachable = 0, //未连接网络 AFNetworkReachabilityStatusReachableViaWWAN = 1, //蜂窝网络 AFNetworkReachabilityStatusReachableViaWiFi = 2, //wifi */其他通知 网络状态变化

用户评论

放血

终于有时间开始学习iOS开源项目了!

    有10位网友表示赞同!

无寒

想了解一下原生网络请求和AFNetworking的区别,哪个更适合新手入门?

    有17位网友表示赞同!

蔚蓝的天空〃没有我的翅膀

之前用过AFNetworking,感觉还挺好用的,可以分享一下一些实际项目案例么?

    有9位网友表示赞同!

聽風

iOS网络请求这块一直没深入学习过,看看这个项目教程能不能给我带来启发。

    有9位网友表示赞同!

残花为谁悲丶

开源项目果然有很多实用的代码片段,可以借鉴很多的设计思路

    有10位网友表示赞同!

惯例

最近在开发一个App需要用到网络请求,不知道选择哪种方式比较好?

    有17位网友表示赞同!

抓不住i

AFNetworking真的太强大了吧,感觉对网络请求的需求都能满足。

    有18位网友表示赞同!

軨倾词

这个课程教程是不是比较容易理解啊?打算跟着学习看看。

    有8位网友表示赞同!

心安i

对iOS原生开发感興趣,正好有机会深入了解一下网络请求机制

    有12位网友表示赞同!

揉乱头发

喜欢看开源项目代码,能看到别人怎么解决实际问题挺好学的

    有17位网友表示赞同!

小清晰的声音

希望这个项目能涵盖一些比较高级的网络请求技巧,比如异步请求和错误处理

    有9位网友表示赞同!

迁心

学习了这些知识以后,可以尝试自己开发一个简单的小程序来应用

    有16位网友表示赞同!

孤独症

最近准备开始iOS开发,这个项目刚好对我的学习很有帮助

    有7位网友表示赞同!

孤败

开源项目不仅可以直接使用,还可以学习到其他人的编程思想

    有10位网友表示赞同!

病态的妖孽

如果可以的话,希望这个教程里面包含一些实际案例的讲解

    有20位网友表示赞同!

(り。薆情海

现在很多App都需要用到网络请求功能,掌握这些技能真的很重要

    有16位网友表示赞同!

柠夏初开

学习完这个项目以后,我可以更好地构建我的iOS应用程序?

    有11位网友表示赞同!

南宫沐风

我一直在使用AFNetworking,这个课程能让我更深入地了解它吗?

    有11位网友表示赞同!

何必锁我心

开源项目的质量有时候很高,值得去认真研究和学习

    有20位网友表示赞同!

【深入iOS开源项目:原生网络请求与AFNetworking 3.1实践指南】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:《38°C爱情》:现实生活里,梦想隐藏,为生计奔波 下一篇:探索#震撼人心的励志书籍之旅