前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络杂谈

网络杂谈

作者头像
拉维
发布2019-08-12 15:54:17
6010
发布2019-08-12 15:54:17
举报
文章被收录于专栏:iOS小生活

NSURL

先来聊聊NSURL吧,NSURL实际上就是对网址字符串的一个封装。而之所以进行这个封装,就是因为请求网址字符串中包括协议类型、服务器地址、端口号、资源层级、文件名等等(这些项目是按照一定的规则组合在一起的),我们要在字符串中获取到其中某一项,那就要自己写一个正则表达式来获取到,这是很不方便的;而NSURL就可以将这个网址字符串分解成固定特有的子字符串,这样就方便了系统的调用以及开发人员的debug。

如下图所示:

如果在网址字符串中,我要找到服务器地址或者是端口号或者是协议类型,那么我就要写大量的正则表达式来进行匹配。而将其封装成NSURL之后,就很方便了,如下都是NSURL的属性:

代码语言:javascript
复制
@property (nullable, readonly, copy) NSString *absoluteString;
@property (readonly, copy) NSString *relativeString; // The relative portion of a URL.  If baseURL is nil, or if the receiver is itself absolute, this is the same as absoluteString
@property (nullable, readonly, copy) NSURL *baseURL; // may be nil.
@property (nullable, readonly, copy) NSURL *absoluteURL; // if the receiver is itself absolute, this will return self.

/* Any URL is composed of these two basic pieces.  The full URL would be the concatenation of [myURL scheme], ':', [myURL resourceSpecifier]
 */
@property (nullable, readonly, copy) NSString *scheme;
@property (nullable, readonly, copy) NSString *resourceSpecifier;

/* If the URL conforms to rfc 1808 (the most common form of URL), the following accessors will return the various components; otherwise they return nil.  The litmus test for conformance is as recommended in RFC 1808 - whether the first two characters of resourceSpecifier is @"//".  In all cases, they return the component's value after resolving the receiver against its base URL.
 */
@property (nullable, readonly, copy) NSString *host;
@property (nullable, readonly, copy) NSNumber *port;
@property (nullable, readonly, copy) NSString *user;
@property (nullable, readonly, copy) NSString *password;
@property (nullable, readonly, copy) NSString *path;
@property (nullable, readonly, copy) NSString *fragment;
@property (nullable, readonly, copy) NSString *parameterString;
@property (nullable, readonly, copy) NSString *query;
@property (nullable, readonly, copy) NSString *relativePath; // The same as path if baseURL is nil

URL,全称是Uniform Resource Locator的缩写,即“统一资源定位符”,因此它既可以表示网络资源的路径,也可以表示本地资源的路径。

本地文件的路径要在资源路径前面加上file://,所以,当我们根据资源路径字符串来创建一个本地文件的URL的时候,需要使用fileURLWithPath方法,而不是使用URLWithString。如下所示:

NSURLRequest

NSURLRequest实际上是对NSURL进一步的包装。

一个NSURL实际上就代表了一个网络请求的地址,而一个Http请求,除了包含网络请求的地址,还需要包含请求方法、协议版本、编码类型等信息,而这些信息是简简单单的一个NSURL所携带不了的,所以需要对NSURL进行一个封装,封装成NSURLRequest。

在APP中,任何与网络相关的操作,都是通过NSURLRequest进行的。比如WebView加载网页:

代码语言:javascript
复制
[webview loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"blabla"]]];

NSURLSession

总的来说,NSURLSession就是负责网络请求的接收、发送以及处理,用大白话讲就是,我们传入一个request,session将该request进行各种处理。

我们将一个浏览器理解成是一个session,一个session里面是可以创建多个网络请求,这可以类比成,一个浏览器可以打开多个网页。

代码语言:javascript
复制
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *urlsession = [NSURLSession sessionWithConfiguration:configuration];

如上面代码所示,我们创建session的时候,是需要传入一个configuration配置对象,这个配置对象可以配置session的各种策略,比如Cache策略、cookie策略等。在APP中,我们可以创建不同配置的多个session。浏览器中有无痕模式和普通模式浏览,这两种模式实际上就是两种不同配置的session。

那么session是如何处理request的呢?session会将request封装成一个NSURLSessionTask,然后通过task来控制网络请求的状态(比如开始、取消),以及监测网络请求的进度。如下图所示:

接下来我们再详细看一下NSURLSession的组织结构

上面也说到了,session与session之间的不同之处在于其configuration的不同。我们可以通过NSURLSessionDelegate来监听网络请求的各个状态。

总的来说,我们可以传入一个configuration来创建一个session,代码如下:

代码语言:javascript
复制
@property (class, readonly, strong) NSURLSession *sharedSession;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
                  delegate:(nullable id <NSURLSessionDelegate>)delegate 
                  delegateQueue:(nullable NSOperationQueue *)queue;

然后通过session将NSURLRequest封装成一个NSURLSessionTask,根据task的用途不同,我们可以将task分为如下四种:

  • dataTask:处理简单的数据流,如JSON数据;
  • downloadTask:大数据下载,可实现断点续传,可以监听并显示下载进度;
  • uploadTask:上传数据;
  • streamTask:流数据。

通过task我们可以管理请求的状态以及监听进度;我们也可以通过NSURLSessionDelegate来监听请求的进程状态。

NSURLSessionTask

上文道,可利用NSURLSession对象将NSURLRequest对象封装成一个NSURLSessionTask,之所以要进行这一层封装,就是为了方便管理网络请求的状态以及监控其网络进程。

NSURLSessionTask的状态(state)有如下四种:

代码语言:javascript
复制
typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {
    NSURLSessionTaskStateRunning = 0,                     /* The task is currently being serviced by the session */
    NSURLSessionTaskStateSuspended = 1,
    NSURLSessionTaskStateCanceling = 2,                   /* The task has been told to cancel.  The session will receive a URLSession:task:didCompleteWithError: message. */
    NSURLSessionTaskStateCompleted = 3,                   /* The task has completed and the session will receive no more delegate notifications */
};

针对NSURLSessionTask的操作有如下三种:

代码语言:javascript
复制
- (void)suspend;//挂起
- (void)resume;//恢复
- (void)cancel;//取消

一开始生成一个NSURLSessionTask对象后,该sessionTask默认是挂起(NSURLSessionTaskStateSuspended)的状态,然后我们使用 resume 方法来开始执行该task。

那么我们该如何获取到网络请求的返回数据呢?如下图:

我们可以使用NSURLSession中封装request或者是URL的方法中的block回调来监听请求的最终状态并获取返回数据;也可以通过NSURLSessionTaskDelegate中的各个代理方法来监听网络请求的进程,并处理对应的返回数据

接下来说一个题外话。在iOS9之后,苹果新增了一个ATS(APP Transport Security)特性,默认要求都是用https进行请求。所以在iOS9之后,如果我们程序中使用了Http的请求,那么苹果就会报错,此时我们要在info.plist文件中修改ATS的默认值,如下图所示:

iOS系统框架整个网络请求的流程如下:

  1. 将网址字符串封装成NSURL,然后将NSURL封装成NSURLRequest;
  2. 创建一个NSURLSessionConfiguration对象,并进行对应的个性化配置,然后将之传入生成一个NSURLSession;
  3. 使用NSURLSession对象将NSURLRequest对象封装成NSURLSessionTask对象;
  4. 通过对task进行resume、cancel等操作来控制网络请求的状态;
  5. 可以通过block handler或者代理来监听请求进程,并处理数据。

开源网络框架杂谈

上文聊了iOS系统网络请求框架的基本使用,我们了解到,对于一个网络请求,我们需要对其进行大量的设置,比如网络请求方式、数据可解析格式、缓存方式等等;而且网络请求成功以后的回调方式也不是特别友好,并且还需要自己解析JSON数据;而且好自己控制网络请求的开始、取消......所以,面对iOS系统网络框架进行网络请求的时候,如果我们的请求比较复杂,都会导致网络请求相关的代码急于增加,而且重复代码非常多。

所以,我们有必要使用开源网络框架来帮我们简化这些繁琐的操作。实际上,无论是哪种开源网络框架,都是对系统网络框架的二次封装。在众多开源网络框架中,我们最常使用的,也是最有名的是AFNetworking。

那么我们怎么样将开源框架集成到我们的项目中呢?接下来我详细介绍一下使用Cocoapods来管理第三方库的原理

首先,在MyProject文件所在的文件夹下,建立一个Podfile文件;

然后,根据相关语法规则,去在Podfile中输入想要集成的代码;

第三步,执行pod install,此时,cocoapods就会根据Podfile的内容去下载相关第三方框架的代码,然后将这些下载好的代码组合生成一个名为Pods的project

第四步,将Pods project和MyProject 组合,自动生成一个workspace

那么,Cocoapods是如何找到这个第三方库的呢

首先,我们自己写好一个公用组件,然后将这个组件托管到一个平台上,比如托管到GitHub上面;

然后在cocoaPods服务器中配置该公用组件,配置组件的名字,以及其下载地址;

这样当其他人使用Cocoapods安装我这个公用组件的时候,Cocoapods会通过名字在pods服务器中寻找是否有该名称的组件,如果有就通过地址下载该组件。

以上。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档