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

NSURLSession与NSURLConnection区别

作者头像
timhbw
发布2018-05-03 12:05:12
1.4K0
发布2018-05-03 12:05:12
举报
文章被收录于专栏:Timhbw博客Timhbw博客

2017-05-0217:47:05 发表评论 425℃热度

目录

今天去面试,被问了一道AFNetworking2.0和3.0有什么区别,当时心想,这谁不知道啊,随口答到:2.0使用的NSURLConnection,3.0使用的是NSURLSession,人家又问NSURLSesstion和NSURLConnection有什么区别,瞬间傻眼了,支支吾吾只是说出了缓存策略的不同。亡羊补牢,为时未晚,这篇博客就讲解一下它们两者到底有什么区别。

NSURLSession与NSURLConnection区别
NSURLSession与NSURLConnection区别
使用现状

NSURLSession是NSURLConnection的替代者,在2013年苹果全球开发者大会上(WWDC2013)随iOS7一起发布的,是对NSURLConnection进行了重构优化后的新的网络接口。从iOS9开始,NSURLConnection中发送请求的两个方法已经过期(同步请求,异步请求),初始化网络连接的方法也被设置为过期,系统不再推荐使用,建议使用NSURLSession发送网络请求。NSURLConnection被废弃的主要接口:

  1. - (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate startImmediately:(BOOL)startImmediately NS_DEPRECATED(10_5, 10_11, 2_0, 9_0, "Use NSURLSession (see NSURLSession.h)") __WATCHOS_PROHIBITED;
  2. - (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate NS_DEPRECATED(10_3, 10_11, 2_0, 9_0, "Use NSURLSession (see NSURLSession.h)") __WATCHOS_PROHIBITED;
  3. + (nullable NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate NS_DEPRECATED(10_3, 10_11, 2_0, 9_0, "Use NSURLSession (see NSURLSession.h)") __WATCHOS_PROHIBITED;
  4. //异步请求
  5. + (void)sendAsynchronousRequest:(NSURLRequest*) request
  6.                           queue:(NSOperationQueue*) queue
  7.               completionHandler:(void (^)(NSURLResponse* __nullable response, NSData* __nullable data, NSError* __nullable connectionError)) handler NS_DEPRECATED(10_7, 10_11, 5_0, 9_0, "Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h") __WATCHOS_PROHIBITED;
  8. //同步请求
  9. + (nullable NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse * __nullable * __nullable)response error:(NSError **)error NS_DEPRECATED(10_3, 10_11, 2_0, 9_0, "Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h") __WATCHOS_PROHIBITED;
普通任务和上传

NSURLSession针对下载/上传等复杂的网络操作提供了专门的解决方案,针对普通、上传和下载分别对应三种不同的网络请求任务:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask。创建的task都是挂起状态,需要resume才能启动。

当服务器返回的数据较小时,NSURLSession与NSURLConnection执行普通任务的操作步骤没有区别。 执行上传任务时,NSURLSession与NSURLConnection一样需要设置POST请求的请求体进行上传。

下载任务方式

NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况。

而使用NSURLSessionUploadTask下载文件,会默认下载到沙盒中的tem文件中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。(后面会详细说)

请求方法的控制

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

NSURLSession有三个控制方法,取消(cancel)、暂停(suspend)、继续(resume),暂停以后可以通过继续恢复当前的请求任务。

断点续传的方式

NSURLConnection进行断点下载,通过设置访问请求的HTTPHeaderField的Range属性,开启运行循环,NSURLConnection的代理方法作为运行循环的事件源,接收到下载数据时代理方法就会持续调用,并使用NSOutputStream管道流进行数据保存。

NSURLSession进行断点下载,当暂停下载任务后,如果downloadTask(下载任务)为非空,调用cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler这个方法,这个方法接收一个参数,完成处理代码块,这个代码块有一个NSData参数resumeData,如果resumeData非空,我们就保存这个对象到视图控制器的resumeData属性中,在点击再次下载时,通过调用[ [self.session downloadTaskWithResumeData:self.resumeData]resume]方法进行继续下载操作

经过以上比较可以发现,使用NSURLSession进行断点下载更加便捷.

配置信息

NSURLSession的构造方法(sessionWithConfiguration:delegate:delegateQueue)中有一个NSURLSessionConfiguration类的参数可以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,资源管理,网络超时等配置。NSURLConnection不能进行这个配置,相比较与NSURLConnection依赖与一个全局的配置对象,缺乏灵活性而言,NSURLSession有很大的改进了。(关于配置信息,后面会讲解到)

通过以上几点,大概知道了NSURLSession和NSURLConnection的区别,想必下载再遇到这样的问题不会支支吾吾了。下面来点NSURLSession的干货。

干货开始

NSURLSession

NSURLSession 为 HTTP 数据传输提供一系列的接口,而使用 NSURLSession 总共只需要三步:

  1. 创建NSURLSession对象
  2. 通过 NSURLSession 的实例创建 Task
  3. 执行 Task
如何获取Session对象

1.获取默认的 Session 对象

  1. /*
  2.  * 用于基本的网络请求,可以几行代码就获取 URL 的内容,使用简单
  3.  * 无法不断的获取服务器返回的数据
  4.  * 无法修改默认的连接行为
  5.  * 身份验证的能力有限
  6.  * 任务在后台时无法上传和下载
  7.  */
  8. + (NSURLSession *)sharedSession;

2.自定义 Session 对象

  1. // 不用代理
  2. + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
  3. // 用代理
  4. + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration
  5.                                   delegate:(nullable id <NSURLSessionDelegate>)delegate
  6.                              delegateQueue:(nullable NSOperationQueue *)queue;

在使用自定义方式创建NSURLSession对像时,都需要传入一个NSURLSessionConfiguration参数,这个参数是对Session的网络请求的基本配置。那这个NSURLSessionConfiguration都有哪些配置呢?接着往下看

NSURLSessionConfiguration

有三个方法来创建NSURLSessionConfiguration:

  • defaultSessionConfiguration 使用全局的cache,cookie,使用硬盘来缓存数据。
  • ephemeralSessionConfiguration 临时session配置,与默认配置相比,这个配置不会将缓存、cookie等存在本地,只会存在内存里,所以当程序退出时,所有的数据都会消失
  • backgroundSessionConfiguration 后台session配置,与默认配置类似,不同的是会在后台开启另一个线程来处理网络数据。

一旦创建了NSURLSessionConfiguration就可以给它设置各种属性

看NSURLSessionConfiguration的头文件:

  1. @interface NSURLSessionConfiguration : NSObject <NSCopying>
  2. /* 三种创建方式 */
  3. + (NSURLSessionConfiguration *)defaultSessionConfiguration;
  4. + (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
  5. + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);
  6. /* 当使用上述第三种方式创建后台sessionConfiguration时可以读到初始化时传入的唯一标识,其他创建方式都为空 */
  7. @property (nullable, readonly, copy) NSString *identifier;
  8. /*
  9. 缓存策略,默认值是NSURLRequestUseProtocolCachePolicy
  10.  */
  11. @property NSURLRequestCachePolicy requestCachePolicy;
  12. /* 给request指定每次接收数据超时间隔,如果下一次接受新数据用时超过该值,则发送一个请求超时给该request。默认为60s */
  13. @property NSTimeInterval timeoutIntervalForRequest;
  14. /* 给指定resource设定一个超时时间,resource需要在时间到达之前完成。默认是7天。 */
  15. @property NSTimeInterval timeoutIntervalForResource;
  16. /* 指定网络传输类型。精切指出传输类型,可以让系统快速响应,提高传输质量,延长电池寿命等。
  17. typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType)
  18. {
  19. NSURLNetworkServiceTypeDefault = 0,    // 普通网络传输,默认使用这个
  20. NSURLNetworkServiceTypeVoIP = 1,    // 网络语音通信传输,只能在VoIP使用
  21. NSURLNetworkServiceTypeVideo = 2,    // 影像传输
  22. NSURLNetworkServiceTypeBackground = 3, // 网络后台传输,优先级不高时可使用。对用户不需要的网络操作可使用
  23. NSURLNetworkServiceTypeVoice = 4       // 语音传输
  24. };
  25.  */
  26. @property NSURLRequestNetworkServiceType networkServiceType;
  27. /* 是否使用蜂窝网络,默认是yes. */
  28. @property BOOL allowsCellularAccess;
  29. /* 是否由系统根据性能自动裁量后台任务。默认值是NO。同sessionSendsLaunchEvent一样,只对后台configuration有效。 */
  30. @property (getter=isDiscretionary) BOOL discretionary NS_AVAILABLE(10_10, 7_0);
  31. /*
  32. 如果要为app的插件提供session,需要给这个值赋值
  33.  */
  34. @property (nullable, copy) NSString *sharedContainerIdentifier NS_AVAILABLE(10_10, 8_0);
  35. /*
  36.  表示当后台传输结束时,是否启动app.这个属性只对 后台sessionConfiguration 生效,其他configuration类型会自动忽略该值。默认值是YES。
  37.  */
  38. @property BOOL sessionSendsLaunchEvents NS_AVAILABLE(NA, 7_0);
  39. /*
  40. 指定了会话连接中的代理服务器。同样地,大多数面向消费者的应用程序都不需要代理,所以基本上不需要配置这个属性,默认为NULL
  41. */
  42. @property (nullable, copy) NSDictionary *connectionProxyDictionary;
  43. /* 确定是否支持SSLProtocol版本的会话
  44.  */
  45. @property SSLProtocol TLSMinimumSupportedProtocol;
  46. /*
  47. 确定是否支持SSLProtocol版本的会话
  48. */
  49. @property SSLProtocol TLSMaximumSupportedProtocol;
  50. /*
  51. 它可以被用于开启HTTP管道,这可以显着降低请求的加载时间,但是由于没有被服务器广泛支持,默认是禁用的
  52.  */
  53. @property BOOL HTTPShouldUsePipelining;
  54. /*
  55. 默认为yes,是否提供来自shareCookieStorge的cookie,如果想要自己提供cookie,可以使用HTTPAdditionalHeaders来提供。
  56.  */
  57. @property BOOL HTTPShouldSetCookies;
  58. /* Policy for accepting cookies.  This overrides the policy otherwise specified by the cookie storage. */
  59. @property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy;
  60. /*
  61. 指定了一组默认的可以设置出站请求的数据头。这对于跨会话共享信息,如内容类型,语言,用户代理,身份认证,是很有用的。
  62. 例如:
  63.     @{@"Accept": @"application/json",
  64.      @"Accept-Language": @"en",
  65.      @"Authorization": authString,
  66.      @"User-Agent": userAgentString
  67.    }
  68.  */
  69. @property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;
  70. /*
  71. 同时连接一个host的最大数。iOS默认是4.APP是作为一个整体来看的
  72.  */
  73. @property NSInteger HTTPMaximumConnectionsPerHost;
  74. /*
  75. 存储cookie,清除存储,直接set为nil即可。
  76. 对于默认和后台的session,使用sharedHTTPCookieStorage。
  77. 对于短暂的session,cookie仅仅储存到内存,session失效时会自动清除。
  78.  */
  79. @property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage;
  80. /*
  81. 证书存储,如果不使用,可set为nil.
  82. 默认和后台session,默认使用的sharedCredentialStorage.
  83. 短暂的session使用一个私有存储在内存中。session失效会自动清除。
  84.  */
  85. @property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage;
  86. /*
  87. 缓存NSURLRequest的response。
  88. 默认的configuration,默认值的是sharedURLCache。
  89. 后台的configuration,默认值是nil
  90. 短暂的configuration,默认一个私有的cache于内存,session失效,cache自动清除。
  91. */
  92. @property (nullable, retain) NSURLCache *URLCache;
  93. /* Enable extended background idle mode for any tcp sockets created.    Enabling this mode asks the system to keep the socket open
  94.  *  and delay reclaiming it when the process moves to the background (see https://developer.apple.com/library/ios/technotes/tn2277/_index.html)
  95.  */
  96. @property BOOL shouldUseExtendedBackgroundIdleMode NS_AVAILABLE(10_11, 9_0);
  97. /*
  98. 处理NSURLRequest的NSURLProtocol的子类。
  99. 重要:对后台Session失效。
  100.  */
  101. @property (nullable, copy) NSArray<Class> *protocolClasses;
  102. @end

现在,我们知道如何来创建一个Session对象了,创建完Session对象,根据一个Request对象我们就可以发送网络请求了。下面看一下NSURLSession的头文件中的这些方法,如图:

NSURLSession与NSURLConnection区别
NSURLSession与NSURLConnection区别

从这些方法中得知,分别返回了NSURLSessionDataTaskNSURLSessionUploadTaskNSURLSessionDownloadTaskNSURLSessionStreamTask 这四个类的对象,那么这四个类是干什么呢?我们接着往下看。

URLSessionTask

NSURLSessionTask是一个抽象类,其下有4个实体子类可以直接使用:NSURLSessionDataTaskNSURLSessionUploadTaskNSURLSessionDownloadTaskNSURLSessionStreamTask。这四个子类封装了现代程序四个最基本的网络任务:获取数据,比如JSON或者XML,上传文件和下载文件还有数据流的获取。

NSURLSession与NSURLConnection区别
NSURLSession与NSURLConnection区别

NSURLSession比NSURLConnection最方便的地方就是任务可以暂停,继续。在网络请求中,真正去执行下载或者上传任务的就是URLSessionTask,我们来看一下它常用的方法:

- (void)resume; 当使用NSURLSession创建一个NSURLSessionTask任务时,要手动调用此方法,任务才会开启,而NSURLConnection默认开启。

- (void)suspend; 暂停任务方法,手动调用会暂停当前任务,再次开启此任务时,会从紧接上次任务开始,会面会说到如何暂停任务再开启任务。

- (void)cancel; 取消任务。

NSURLSessionTask还有个属性,@property (readonly) NSURLSessionTaskState state;此属性标识当前任务的状态,枚举类型

  1. typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {
  2. NSURLSessionTaskStateRunning = 0,                     /* 正在执行 */
  3. NSURLSessionTaskStateSuspended = 1,                   /* 暂停状态 */
  4. NSURLSessionTaskStateCanceling = 2,                   /* 取消状态*/
  5. NSURLSessionTaskStateCompleted = 3,                   /* 任务完成状态 */
  6. }

上面说到的四个类,都直接或间接继承NSURLSessionTask,所有NSURLSessionTask的方法或者属性这四个类都有,那么,简单说一下这四个类都是干什么的。

NSURLSessionDataTask

NSURLSessionDataTask是开发中使用频率最高的,我们平常使用的GET和POST请求都是通过它来实现的,如果请求的数据简单并且不需要对获取的数据进行复杂操作,我们使用 Block 解析返回的数据即可。具体代码如下:

简单 Get 请求
  1. /**
  2.  *  简单 GET 请求
  3.   */
  4. - (void)getWithsharedSession
  5. {
  6.   // 获取默认 Session
  7.   NSURLSession *session = [NSURLSession sharedSession];
  8.   // 创建 URL
  9.   NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/s?wd=test"];
  10.   // 创建任务 task
  11.   NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  12.     // 获取数据后解析并输出
  13.      NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  14.     NSLog(@"%@",dataStr);
  15.   }];
  16.   // 启动任务
  17.   [task resume];
  18. }
简单 POST 请求
  1. /**
  2.  *  简单 Post 请求,POST 和 GET 请求在于对 request 的处理不同,其余和 GET 相同
  3.  */
  4. - (void)postWithSharedSession
  5. {
  6.   // 获取默认 Session
  7.   NSURLSession *session = [NSURLSession sharedSession];
  8.   // 创建 URL
  9.   NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
  10.   // 创建 request
  11.   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  12.   // 请求方法
  13. request.HTTPMethod = @"POST";
  14.   // 请求体
  15. request.HTTPBody = [@"username=1234&pwd=4321" dataUsingEncoding:NSUTF8StringEncoding];
  16.   // 创建任务 task
  17.   NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  18.           // 获取数据后解析并输出
  19.           NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
  20.   }];
  21.   // 启动任务
  22.   [task resume];
  23. }

另外我们也可以设置session的代理来实时的监听数据,我们可以使用NSURLSession的+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;这两个方法来设置代理,具体的协议为NSURLSessionDelegate,它有四个直接或间接子协议NSURLSessionTaskDelegateNSURLSessionDownloadDelegate和 NSURLSessionStreamDelegateNSURLSessionDataDelegate。具体代理方法如下:

  1. //创建有代理的session
  2. - (void)sessionDataDelegate
  3. {
  4.     // 创建带有代理方法的自定义 session
  5.     NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
  6.     // 创建任务
  7.     NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/login?username=1234&pwd=4321"]]];
  8.     // 启动任务
  9.     [task resume];
  10. }
  11. #pragma mark -
  12. #pragma mark - NSURLSessionDelegate
  13. // 1. 接收到服务器的响应
  14. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
  15. {
  16.     NSLog(@"接收到服务器的响应");
  17.     // 必须设置对响应进行允许处理才会执行后面两个操作。
  18.     completionHandler(NSURLSessionResponseAllow);
  19. }
  20. // 2. 接收到服务器的数据(可能调用多次)
  21. - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
  22.     // 处理每次接收的数据
  23.     NSLog(@"接受到服务器的数据%s",__func__);
  24. }
  25. // 3. 请求成功或者失败(如果失败,error有值)
  26. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
  27.     // 请求完成,成功或者失败的处理
  28.     NSLog(@"SessionTask %s",__func__);
  29. }
NSURLSessionDownloadTask

NSURLSessionDownloadTask在下载文件的时候,是将数据一点点地写入本地的临时文件。所以在 completionHandler 这个 block 里,我们需要把文件从一个临时地址移动到一个永久的地址保存起来:

  1. /**
  2.  *  NSURLSessionDownloadTask 下载任务
  3.  */
  4. - (void)downLoad
  5. {
  6.     NSURLSession *session = [NSURLSession sharedSession];
  7.     NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"] ;
  8.     NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
  9.         // location 是沙盒中 tmp 文件夹下的一个临时 url,文件下载后会存到这个位置,由于 tmp 中的文件随时可能被删除,所以我们需要自己需要把下载的文件挪到 Caches 文件夹中
  10.         NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
  11.         // 剪切文件
  12.         [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];
  13.         NSLog(@"%@",[NSThread currentThread]);
  14.         //切记当前为子线程,
  15.         dispatch_async(dispatch_get_main_queue(), ^{
  16. self.imageView.image = [UIImage imageNamed:path];
  17.         });
  18.     }];
  19.     // 启动任务
  20.     [task resume];
  21. }

代理方法下载

  1. /**
  2.  *  NSURLSessionDownloadTask 代理
  3.  */
  4. - (void)sessionDownloadTaskDelegate
  5. {
  6.   // 创建带有代理方法的自定义 session
  7.   NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
  8.   // 创建任务
  9.   NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"]];
  10.   // 启动任务
  11.   [task resume];
  12. }
  13. #pragma mark -
  14. #pragma mark -NSURLSessionDownloadDelegate
  15. /**
  16.  *  写入临时文件时调用
  17.  *  @param bytesWritten              本次写入大小
  18.  *  @param totalBytesWritten         已写入文件大小
  19.  *  @param totalBytesExpectedToWrite 请求的总文件的大小
  20.  */
  21. - (void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
  22. {
  23.     //可以监听下载的进度
  24.   CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
  25.   NSLog(@"downloadTask %f",progress);
  26. }
  27. // 2. 下载完成调用
  28. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
  29. {
  30.   // location 还是一个临时路径,需要自己挪到需要的路径(caches 文件夹)
  31.   NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
  32.   [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
  33.   NSLog(@"downloadTask 移动文件路径");
  34. }
断点续传

说一下开发中经常用到的断点续传。在开发中,我们经常由于某种原因,在下载或上传的时候往往不能一次性下载或上传完,有可能下载或上传了一半就终止了,这时候当条件满足继续下载或上传时,我们不希望从头开始,这时候就可以使用断点续传。它的大概思路是:

  • 某种限制,续传暂停
  • 将暂停后数据(当前数据)保存起来--_resumeData = resumeData;
  • 条件允许续传时,使用resumeData创建新的NSURLSessionTask

代码:

  1. - (IBAction)startDowning:(id)sender {
  2.     if (_resumeData) {
  3. _downloadTask = [_session downloadTaskWithResumeData:_resumeData];
  4.     }else {
  5. _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
  6. _request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://image.baidu.com/search/down?tn=download&ipn=dwnl&word=download&ie=utf8&fr=result&url=http%3A%2F%2Fb.zol-img.com.cn%2Fdesk%2Fbizhi%2Fimage%2F6%2F960x600%2F1427787678554.jpg&thumburl=http%3A%2F%2Fimg3.imgtn.bdimg.com%2Fit%2Fu%3D1996019669%2C1779575266%26fm%3D21%26gp%3D0.jpg"]];
  7. _downloadTask = [_session downloadTaskWithRequest:_request];
  8.     }
  9.     [_downloadTask resume];
  10. }
  11. - (IBAction)stopDowning:(id)sender {
  12.     if (_downloadTask) {
  13.         __weak typeof (self)weakSelf = self;
  14.         [_downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
  15.             NSLog(@"%@",resumeData);
  16. weakSelf.resumeData = resumeData;
  17. weakSelf.downloadTask = nil;
  18.         }];
  19.     }
  20. }
  21. #pragma mark -
  22. #pragma mark - NSURLSessionDownloadDelegate
  23. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
  24. didFinishDownloadingToURL:(NSURL *)location {
  25.     NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
  26.     // 剪切文件
  27.     [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];
  28.     dispatch_async(dispatch_get_main_queue(), ^{
  29. self.imageView.image = [UIImage imageNamed:path];
  30.     });
  31. }
  32. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
  33.       didWriteData:(int64_t)bytesWritten
  34.  totalBytesWritten:(int64_t)totalBytesWritten
  35. totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
  36.     CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
  37.     NSLog(@"downloadTask %f",progress);
  38.     dispatch_async(dispatch_get_main_queue(), ^{
  39. self.progressView.progress = progress;
  40.     });
  41. }

注意:上面的代码是不会断点续传的,原因是这个图片的url不支持断点续传,在断点续传时,要和服务器配合好。

NSURLSessionUploadTask

在 NSURLSession 中,文件上传主要使用两种方式:

  1. - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
  2. - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;

我们这里使用第二个方法,表单的形式上传数据

  1. - (void)upload {
  2.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.weibo.com/2/statuses/public_timeline.json"]];
  3.     //设置HTTP请求方式  GET / POST
  4.     [request setHTTPMethod:@"POST"];
  5.     //设置请求头
  6.     NSString *boundary = @"hwg";
  7.     [request setValue:[NSString stringWithFormat: @"multipart/form-data;%@", boundary]forHTTPHeaderField:@"Content-type"];
  8.     //设置请求体
  9.     //获取上传的图片的data
  10.     NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"xiaoxin" ofType:@"jpeg"]];
  11.     //此处添加需要看清楚内容
  12.     NSData *body =  [self httpFormDataBodyWithBoundary:boundary params:@{@"access_token":@"2.00cYYKWF6EKpiB3883361b1dJiZ4eD",@"status":@"哈哈,这是我测试NSURLSession上传文件的微博"} fieldName:@"pic" fileName:@"pic.png" fileContentType:@"image/png" data:data];
  13.     NSURLSession *session = [NSURLSession sharedSession];
  14.     NSURLSessionUploadTask *upload_task = [session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  15.         NSLog(@"upload  success");
  16.     }];
  17.     //必须要 resume
  18.     [upload_task resume];
  19. }
  20. #pragma mark-拼接请求体
  21. - (NSData *)httpFormDataBodyWithBoundary:(NSString *)boundary
  22.                                  params:(NSDictionary *)params
  23.                               fieldName:(NSString *)fieldName
  24.                                fileName:(NSString *)fileName
  25.                         fileContentType:(NSString *)fileContentType
  26.                                    data:(NSData *)fileData {
  27.     NSString *preBoundary = [NSString stringWithFormat:@"--%@",boundary];
  28.     NSString *endBoundary = [NSString stringWithFormat:@"--%@--",boundary];
  29.     NSMutableString *body = [[NSMutableString alloc] init];
  30.     //遍历
  31.     for (NSString *key in params) {
  32.         //得到当前的key
  33.         //如果key不是当前的pic,说明value是字符类型,比如name:Boris
  34.         //添加分界线,换行,必须使用\r\n
  35.         [body appendFormat:@"%@\r\n",preBoundary];
  36.         //添加字段名称换2行
  37.         [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
  38.         //添加字段值
  39.         [body appendFormat:@"%@\r\n",[params objectForKey:key]];
  40.     }
  41.     //添加分界线,换行
  42.     [body appendFormat:@"%@\r\n",preBoundary];
  43.     //声明pic字段,文件名为boris.png
  44.     [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
  45.     //声明上传文件的格式
  46.     [body appendFormat:@"Content-Type: %@\r\n\r\n",fileContentType];
  47.     //声明结束符
  48.     NSString *endStr = [NSString stringWithFormat:@"\r\n%@",endBoundary];
  49.     //声明myRequestData,用来放入http  body
  50.     NSMutableData *myRequestData = [NSMutableData data];
  51.     //将body字符串转化为UTF8格式的二进制
  52.     [myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
  53.     //将image的data加入
  54.     [myRequestData appendData:fileData];
  55.     //加入结束符--hwg--
  56.     [myRequestData appendData:[endStr dataUsingEncoding:NSUTF8StringEncoding]];
  57.     return myRequestData;
  58. }

这里我们需要拼接一个表单数据,才能够上传数据。 当然,我们也可以用代理方法来监听上传的进度。

  1. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
  2.    didSendBodyData:(int64_t)bytesSent
  3.     totalBytesSent:(int64_t)totalBytesSent
  4. totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
  5.     CGFloat progress = 1.0 * totalBytesSent / bytesSent;
  6.     NSLog(@"downloadTask %f",progress);
  7. }
结语

以上就是我今天总结的,哪里有问题还希望大家提出意见。其实在开发中,我们很少使用到这些,因为总是有一些牛人为我们封装了各种功能的强大库,比如网络类,最常用的就是AFNetworking。人家的库为什么好用,说白了就是各种情况都考虑到了。所有我们要学的还是人家的编程思想。接下来,我会做一个专题,研究一下各大平常使用到的库,它们到底牛在哪里,敬请阅读!我的博客www.guiyongdong.com

转载自:www.guiyongdong.com

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-05-021,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用现状
  • 普通任务和上传
  • 下载任务方式
  • 请求方法的控制
  • 断点续传的方式
  • 配置信息
  • NSURLSession
    • 如何获取Session对象
    • NSURLSessionConfiguration
    • URLSessionTask
      • NSURLSessionDataTask
        • 简单 Get 请求
        • 简单 POST 请求
      • NSURLSessionDownloadTask
        • 断点续传
      • NSURLSessionUploadTask
        • 结语
        相关产品与服务
        多因子身份认证
        多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档