每日一问19——NSURLSession

2017-10-10  本文已影响157人  巫师学徒

基本简介

2013 年 WWDC 上,Apple 发布了 NSURLConnection 的继任者 NSURLSession,支持 iOS7.0+,而 NSURLCOnnection 在 iOS9 被宣布弃用。

基本使用

设计思路与使用

NSURLsessionTask 是一个抽象类,其下有 3 个实体子类可以直接使用:NSURLSessionDataTask、NSURLSessionUploadTask、NSURLSessionDownloadTask。这 3 个子类封装了现代程序三个最基本的网络任务

NSURLSession.png

NSURLSession 以及相关类为 Http 请求提供了相关接口,为了使用 NSURLSession,需要我们创建一组 session 对象,每一个 session 对象负责执行一组数据传输任务。

与 NSURLConnection 相比,NSURLsession 最直接的改进就是可以配置每个 session 的缓存,协议,cookie,以及证书策略(credential policy),甚至跨程序共享这些信息。这将允许程序和网络基础框架之间相互独立,不会发生干扰。每个 NSURLSession 对象都由一个 NSURLSessionConfiguration 对象来进行初始化,后者指定了刚才提到的那些策略以及一些用来增强移动设备上性能的新选项。

最简单的请求

1.创建session对象,

NSURLSession *session = [NSURLSession sharedSession];

2.创建task对象

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
 NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

    }];

3.执行task

[task resume];
配置config
NSURLSessionConfiguration

在创建会话的时候,我们可以传入一个配置对象来配置当前会话的一些功能。并且系统提供以下三种会话配置供选择使用

@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;

+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
可配置的属性

NSURLSessionConfiguration提供了20多个可配置的属性,下面依次列举这些属性有什么用

NSURLRequestUseProtocolCachePolicy = 0, //指定URL缓存
     
     NSURLRequestReloadIgnoringLocalCacheData = 1, //从原始地址加载,不使用缓存。
     NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // Unimplemented 忽略本地缓存,也忽略代理服务器或其他中间介质的缓存。完全无缓存。
     NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
     
     NSURLRequestReturnCacheDataElseLoad = 2, 无论缓存是否过期,先使用本地缓存,如果无本地缓存,从原始地址加载数据
     NSURLRequestReturnCacheDataDontLoad = 3, 无论缓存是否过期,先使用本地缓存,如果本地无对应数据,那么从原始地址加载,视为请求失败。只取缓存。
     
     NSURLRequestReloadRevalidatingCacheData = 5, // Unimplemented  从原始地址确认缓存数据合法性后使用缓存,否则从原始地址加载

config.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
67179-f5592fa82c6fe4dc.png
typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
     {
     NSURLNetworkServiceTypeDefault = 0,    // Standard internet traffic
     NSURLNetworkServiceTypeVoIP = 1,    // Voice over IP control traffic
     NSURLNetworkServiceTypeVideo = 2,    // Video traffic
     NSURLNetworkServiceTypeBackground = 3, // Background traffic
     NSURLNetworkServiceTypeVoice = 4,       // Voice data
     NSURLNetworkServiceTypeCallSignaling API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) = 11, // Call Signaling
     };
config.connectionProxyDictionary = @
     {
     @"HTTPEnable":@YES,
     (id)kCFStreamPropertyHTTPProxyHost:@"1.2.3.4",
     (id)kCFStreamPropertyHTTPProxyPort:@8080,
     @"HTTPSEnable":@YES,
     (id)kCFStreamPropertyHTTPSProxyHost:@"1.2.3.4",
     (id)kCFStreamPropertyHTTPSProxyPort:@8080
     };
typedef NS_ENUM(NSUInteger, NSHTTPCookieAcceptPolicy) {
     NSHTTPCookieAcceptPolicyAlways,
     NSHTTPCookieAcceptPolicyNever,
     NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain
     };
NSString *userPasswordString = [NSString stringWithFormat:@"%@:%@", user, password];
     NSData * userPasswordData = [userPasswordString dataUsingEncoding:NSUTF8StringEncoding];
     NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
     NSString *authString = [NSString stringWithFormat:@"Basic %@", base64EncodedCredential];
     NSString *userAgentString = @"AppName/com.example.app (iPhone 5s; iOS 7.0.2; Scale/2.0)";
     
     configuration.HTTPAdditionalHeaders = @{@"Accept": @"application/json",
     @"Accept-Language": @"en",
     @"Authorization": authString,
     @"User-Agent": userAgentString};
+ multipathServiceType : 多路径TCP
//     typedef NS_ENUM(NSInteger, NSURLSessionMultipathServiceType)
//     {
    //默认,不使用
//     NSURLSessionMultipathServiceTypeNone = 0,          /* None - no multipath (default) */
    //只有当主链路不能使用时才使用第二条链路
//    NSURLSessionMultipathServiceTypeHandover = 1,       /* Handover - secondary flows brought up when primary flow is not performing adequately. */
    //当主链路不够用时,丢包,延迟等情况,开启第二链路。
//    NSURLSessionMultipathServiceTypeInteractive = 2, /* Interactive - secondary flows created more aggressively. */
    //一起使用,仅开发测试使用
//    NSURLSessionMultipathServiceTypeAggregate = 3    /* Aggregate - multiple subflows used for greater bandwitdh. */
//     }

NSURLSession的代理

NSURLSessionDelegate.png
NSURLSessionDelegate

会话接收的最后一个消息。会话会变无效,因为系统性的错误或者明确的被指定无效,在这种情况下error的值为nil。

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error 

当一个认证挑战连接发生的时候,这个代理将给客户端一个机会去提供身份验证凭证(authenticationcredentials)。如果没有实现将执行默认的处理

(NSURLSessionAuthChallengePerformDefaultHandling)。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler 

如果应用收到-application:handleEventsForBackgroundURLSession:completionHandler:的消息,这个代理方法将收到这个消息用以表明:该会话中,所有过去队列化的消息已经被交付。此时去调用completionHandler或者去进行内部更新后调用completionHandler都是安全的。

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session

NSURLSessionTaskDelegate

当请求被延迟执行时调用,可以选择撤销之前的请求并重新创建一个或者继续沿用之前的请求

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willBeginDelayedRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLSessionDelayedRequestDisposition disposition, NSURLRequest * _Nullable newRequest))completionHandler

当由于网络不通导致请求等待时,会调用这个方法,每个请求只会调一次,且后台请求不会调用

- (void)URLSession:(NSURLSession *)session taskIsWaitingForConnectivity:(NSURLSessionTask *)task 

客户端告知服务器端需要HTTP重定向。

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler 

该方法的调用取决于认证挑战的类型:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler 

当一个session task需要发送一个新的request body stream到服务器端的时候

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler 

周期性地通知代理发送到服务器端数据的进度

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend

当完成收集统计信息后调用。

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics 

告知该session task已经完成了数据传输任务

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error 

NSURLSessionDataDelegate

将NSURLSessionResponseDisposition的值传递给completionHandler进行回调,来控制任务的行为

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    /*
     typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
     NSURLSessionResponseCancel = 0,
     NSURLSessionResponseAllow = 1,
     NSURLSessionResponseBecomeDownload = 2,
     NSURLSessionResponseBecomeStream  = 3,
     }
     
     NSURLSessionResponseCancel:取消response的载入,同[task cancel].
     NSURLSessionResponseAllow:允许response的载入.
     NSURLSessionResponseBecomeDownload:把该request变为download task.
     NSURLSessionResponseBecomeStream:把该request变为stream task.
     */
}

通知这个data Task已经变成download task。

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask 

通知这个data Task已经变成stream task。

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask 

通知代理此次已经接收到的data。会分批吐出服务端返回的数据

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data

将NSCachedURLResponse传递给completionHandler进行回调,去缓存响应的数据。或者传递nil,不去缓存。

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler

NSURLSessionDownloadDelegate

当下载任务完成的时候被调用,这个代理将把这个文件从被给的位置copy或者移动一个新的位置。因为这个文件将被移除,当这个代理消息返回的时候。 URLSession:task:didCompleteWithError:仍然会被调用

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location 

周期性的通知下载的进度

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite 

告诉代理,下载任务重新开始下载了,如果一个下载任务因出错而失败,这个error中的userInfo字典中的NSURLSessionDownloadTaskResumeData对应的value,即为resume data。

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes 

NSURLSessionStreamDelegate

数据流的连接中读数据的一边已经关闭

- (void)URLSession:(NSURLSession *)session readClosedForStreamTask:(NSURLSessionStreamTask *)streamTask 

数据流的连接中写数据的一边已经关闭

- (void)URLSession:(NSURLSession *)session writeClosedForStreamTask:(NSURLSessionStreamTask *)streamTask

系统已经发现了一个更好的连接主机的路径

- (void)URLSession:(NSURLSession *)session betterRouteDiscoveredForStreamTask:(NSURLSessionStreamTask *)streamTask

task已经完成,并且从底层的网络连接中创建inputStream,outputStream。这将在所有队列化的I/O被完成后调用,此后这个streamTask将不接受任何代理消息

- (void)URLSession:(NSURLSession *)session streamTask:(NSURLSessionStreamTask *)streamTask didBecomeInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream 

与NSURLConnection对比

普通的上传与下载
下载任务方式
请求方法的控制
断点续传的方式
配置信息

相关文章

iOS 网络学习(二)—— NSURLSession
AFNetworking原理:NSURLSession(四)
从 NSURLConnection 到 NSURLSession
AFNetworking源码阅读(三)
NSURLSession与NSURLConnection区别

上一篇 下一篇

猜你喜欢

热点阅读