//
// ViewController.m
// NSURLSession
//
// Created by kuyu on 16/3/1.
// Copyright © 2016年 TCL-YX. All rights reserved.
//
#import "ViewController.h"
#define kImageURL @"http://b.hiphotos.baidu.com/image/pic/item/d788d43f8794a4c274c8110d0bf41bd5ad6e3928.jpg"
#define kDataUrl @"http://api.openweathermap.org/data/2.5/weather?q=London,uk"
@interface ViewController ()<NSURLSessionDataDelegate,NSURLSessionDownloadDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (strong,nonatomic) NSMutableData *myData ;
@property (strong,nonatomic) NSURLSessionDownloadTask *downloadTask ;
@property (strong,nonatomic) NSData *resumeData ;
@end
@implementation ViewController
-(NSMutableData *)myData
{
if (_myData == nil) {
self.myData = [NSMutableData data];
}
return _myData ;
}
- (void)viewDidLoad {
[super viewDidLoad];
/*
URL Session的基本概念
1>>>.三种工作模式
默认会话模式(default):工作模式类似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证授权。
瞬时会话模式(ephemeral):该模式不使用磁盘保存任何数据。所有和会话相关的caches,证书,cookies等都被保存在RAM中,因此当程序使会话无效,这些缓存的数据就会被自动清空。
后台会话模式(background):该模式在后台完成上传和下载,在创建Configuration对象的时候需要提供一个NSString类型的ID用于标识完成工作的后台会话。
2>>>.NSURLSession支持的三种任务
NSURLSession类支持三种类型的任务:加载数据,下载和上传。
二、相关的类
NSURLConnection这个名字,实际上指的是一组构成Foundation框架中URL加载系统的相互关联的组件:NSURLRequest,NSURLResponse,NSURLProtocol,NSURLCache,NSHTTPCookieStorage,NSURLCredentialStorage,以及和它同名的NSURLConnection。
在WWDC 2013中,Apple的团队对NSURLConnection进行了重构,并推出了NSURLSession作为替代。
NSURLSession也是一组相互依赖的类,它的大部分组件和NSURLConnection中的组件相同如NSURLRequest,NSURLCache等。而NSURLSession的不同之处在于,它将NSURLConnection替换为NSURLSession和NSURLSessionConfiguration,以及3个NSURLSessionTask的子类:NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask。
*/
/*
1)使用步骤
使用NSURLSession创建task,然后执行task
(2)关于task
a.NSURLSessionTask是一个抽象类,本身不能使用,只能使用它的子类
b.NSURLSessionDataTask\NSURLSessionUploadTask\NSURLSessionDownloadTask
*/
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark --GET
- (IBAction)getRequest:(id)sender {
//发送get请求
//1.创建NSURLSession对象(可以获取单例对象)
NSURLSession *session = [NSURLSession sharedSession];
//2.根据NSURLSession对象创建一个Task
NSURL *url = [NSURL URLWithString:kDataUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//方法参数说明
/*
注意:该block是在子线程中调用的,如果拿到数据之后要做一些UI刷新操作,那么需要回到主线程刷新
第一个参数:需要发送的请求对象
block:当请求结束拿到服务器响应的数据时调用block
block-NSData:该请求的响应体
block-NSURLResponse:存放本次请求的响应信息,响应头,真实类型为NSHTTPURLResponse
block-NSErroe:请求错误信息
*/
__weak ViewController *mySelf = self ;
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//拿到响应头信息
NSHTTPURLResponse *response1 = (NSHTTPURLResponse *)response ;
NSLog(@"%@/n%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding],response1.allHeaderFields);
mySelf.imageView.image = [UIImage imageWithData:data];
}];
//3.执行Task
//注意:刚创建出来的task默认是挂起状态的,需要调用该方法启动任务(执行任务)
[dataTask resume];
/**********************GET的第二种发送请求********************/
//注意:该方法内部默认会把URL对象包装成一个NSURLRequest对象(默认是GET请求)
//方法参数说明
/*
//第一个参数:发送请求的URL地址
//block:当请求结束拿到服务器响应的数据时调用block
//block-NSData:该请求的响应体
//block-NSURLResponse:存放本次请求的响应信息,响应头,真实类型为NSHTTPURLResponse
//block-NSErroe:请求错误信息
*/
//
// NSURLSessionDataTask *dataTask1 = [session dataTaskWithURL:[NSURL URLWithString:kImageURL] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//
//
// self.imageView.image = [UIImage imageWithData:data];
//
//
// }];
//
// [dataTask1 resume];
}
#pragma mark --POST请求
- (IBAction)postRequest:(id)sender {
//1.创建NSURLSession对象(可以获取单例对象)
NSURLSession *session = [NSURLSession sharedSession];
//2.根据NSURLSession对象创建一个Task
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
//创建一个请求对象,并这是请求方法为POST,把参数放在请求体中传递
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
//拿到响应头信息
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//解析拿到的响应数据
NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
}];
//3.执行Task
//注意:刚创建出来的task默认是挂起状态的,需要调用该方法来启动任务(执行任务)
[dataTask resume];
}
#pragma mark --文件上传
- (IBAction)upRequest:(id)sender {
//在NSURLSession中,文件上传方式主要有以下两种:
//(1)实现文件上传的方法
/*
第一个参数:请求对象
第二个参数:请求体(要上传的文件数据)
block回调:
NSData:响应体
NSURLResponse:响应头
NSError:请求的错误信息
*/
// NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:data completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error)
//
//(2)设置代理,在代理方法中监听文件上传进度
/*
调用该方法上传文件数据
如果文件数据很大,那么该方法会被调用多次
参数说明:
totalBytesSent:已经上传的文件数据的大小
totalBytesExpectedToSend:文件的总大小
*/
// -(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
// {
// NSLog(@"%.2f",1.0 * totalBytesSent/totalBytesExpectedToSend);
// }
/*
NSURLSessionUploadTask *task =
[[NSURLSession sharedSession] uploadTaskWithRequest:request
fromFile:fileName
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}];
[[NSURLSession sharedSession] uploadTaskWithRequest:request
fromData:body
completionHandler:^(NSData data, NSURLResponse response, NSError *error) {
NSLog(@"-------%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
*/
/* 处于安全性考虑,通常我们会使用POST方式进行文件上传,所以较多使用第二种方式.
但是,NSURLSession并没有为我们提供比NSURLConnection更方便的文件上传方式.方法中body处的参数需要填写request的请求体(http协议规定格式的大长串).因为你有90%的可能性用了AFNetworking,即使是自己写的应该也是copy,所以代码就不贴了我们只说方法呵呵哒.
*/
}
- (IBAction)downloadRequest:(id)sender {
[self downLoadOne];
// [self doenLoadtwo];
}
#pragma mark --使用NSURLSession实现大文件(代理方式)
-(void)doenLoadtwo
{
/*
可以监控下载进度
但不能实现断点下载,如果有断点下载的需求,可以阅读另外一篇博文 大文件离线断点下载
遵守协议NSURLSessionDownloadDelegate,实现相应的代理方法
*/
// 获得NSURLSession对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
// 获得下载任务
self.downloadTask = [session downloadTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]];
// 启动任务
[self.downloadTask resume];
}
#pragma mark - <NSURLSessionDownloadDelegate>
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
/*
2.恢复下载的时候调用该方法
fileOffset:恢复之后,要从文件的什么地方开发下载
expectedTotalBytes:该文件数据的总大小
*/
NSLog(@"didResumeAtOffset");
}
/**
* 每当写入数据到临时文件时,就会调用一次这个方法(会调用多次)
* totalBytesExpectedToWrite:总大小
* totalBytesWritten: 已经写入的大小
* bytesWritten: 这次写入多少
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//计算当前的下载进度
NSLog(@"--------%f", 1.0 * totalBytesWritten / totalBytesExpectedToWrite);
}
// 下载完毕就会调用一次这个方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
// location还是一个临时路径,需要自己挪到需要的路径(caches下面)
// 文件将来存放的真实路径
NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
NSLog(@" %@",file);
// 剪切location的临时文件到真实路径
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr moveItemAtURL:location toURL:[NSURL fileURLWithPath:file] error:nil];
}
//任务完成调用 (之前的代理方法已包括)
//- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
//{
// NSLog(@"didCompleteWithError");
//}
#pragma mark --实现断点下载相关代码
-(void)downLoadTask
{
//如果任务,取消了那么以后就不能恢复了
// [self.downloadTask cancel];
//如果采取这种方式来取消任务,那么该方法会通过resumeData保存当前文件的下载信息
//只要有了这份信息,以后就可以通过这些信息来恢复下载
[self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
self.resumeData = resumeData;
}];
//继续下载
//首先通过之前保存的resumeData信息,创建一个下载任务
self.downloadTask = [[NSURLSession sharedSession] downloadTaskWithResumeData:self.resumeData];
[self.downloadTask resume];
}
- (IBAction)stopDown:(id)sender {
[self downloadTask];
}
#pragma mark --下载文件 --代理(普通的下载,图片之类)
-(void)downLoadOne
{
//(1)创建NSURLSession对象,设置代理(默认配置)
//1.创建NSURLSession,并设置代理
/*
第一个参数:session对象的全局配置设置,一般使用默认配置就可以
第二个参数:谁成为session对象的代理
第三个参数:代理方法在哪个队列中执行(在哪个线程中调用),如果是主队列那么在主线程中执行,如果是非主队列,那么在子线程中执行
*/
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//(2)根据Session对象创建一个NSURLSessionDataTask任务(post和get选择)
//创建task
NSURL *url = [NSURL URLWithString:kImageURL];
//注意:如果要发送POST请求,那么请使用dataTaskWithRequest,设置一些请求头信息
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];
//(3)执行任务(其它方法,如暂停、取消等)
//启动task
[dataTask resume];
//其它方法,如取消任务,暂停任务等
//[dataTask cancel];
//[dataTask suspend];
}
#pragma mark --NSURLSessionDataDelegate代理方法
//(4)遵守代理协议,实现代理方法(3个相关的代理方法)
/*
1.当接收到服务器响应的时候调用
session:发送请求的session对象
dataTask:根据NSURLSession创建的task任务
response:服务器响应信息(响应头)
completionHandler:通过该block回调,告诉服务器端是否接收返回的数据
*/
-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler
{
//默认情况下,当接收到服务器响应之后,服务器认为客户端不需要接收数据,所以后面的代理方法不会调用
//如果需要继续接收服务器返回的数据,那么需要调用block,并传入对应的策略
/*
NSURLSessionResponseCancel = 0, 取消任务
NSURLSessionResponseAllow = 1, 接收任务
NSURLSessionResponseBecomeDownload = 2, 转变成下载
NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3, 转变成流
*/
// 允许处理服务器的响应,才会继续接收服务器返回的数据
completionHandler(NSURLSessionResponseAllow);
}
/*
2.当接收到服务器返回的数据时调用
该方法可能会被调用多次
*/
-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data
{
[self.myData appendData:data];
self.imageView.image = [UIImage imageWithData:self.myData];
}
/*
3.当请求完成之后调用该方法
不论是请求成功还是请求失败都调用该方法,如果请求失败,那么error对象有值,否则那么error对象为空
*/
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
{
}
#pragma mark -- 使用NSURLSessionDataTask实现大文件离线断点下载(完整)
-(void)initNSOutputStream
{
//6.1 涉及知识点
//(1)关于NSOutputStream的使用
//1. 创建一个输入流,数据追加到文件的屁股上
//把数据写入到指定的文件地址,如果当前文件不存在,则会自动创建
// NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];
//2. 打开流
//[stream open];
//3. 写入流数据
// [stream write:data.bytes maxLength:data.length];
//4.当不需要的时候应该关闭流
//[stream close];
//(2)关于网络请求请求头的设置(可以设置请求下载文件的某一部分)
//1. 设置请求对象
//1.1 创建请求路径
// NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
//1.2 创建可变请求对象
//NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//1.3 拿到当前文件的残留数据大小
// self.currentContentLength = [self FileSize];
//1.4 告诉服务器从哪个地方开始下载文件数据
// NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
// NSLog(@"%@",range);
//1.5 设置请求头
//[request setValue:range forHTTPHeaderField:@"Range"];
//(3)NSURLSession对象的释放
}
-(void)dealloc
{
//在最后的时候应该把session释放,以免造成内存泄露
// NSURLSession设置过代理后,需要在最后(比如控制器销毁的时候)调用session的invalidateAndCancel或者resetWithCompletionHandler,才不会有内存泄露
// [self.session invalidateAndCancel];
// [self.session resetWithCompletionHandler:^{
//
// NSLog(@"释放---");
// }];
}
/*
(3)关于NSURLSessionConfiguration相关
01 作用:可以统一配置NSURLSession,如请求超时等
02 创建的方式和使用
//创建配置的三种方式
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);
//统一配置NSURLSession
-(NSURLSession *)session
{
if (_session == nil) {
//创建NSURLSessionConfiguration
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//设置请求超时为10秒钟
config.timeoutIntervalForRequest = 10;
//在蜂窝网络情况下是否继续请求(上传或下载)
config.allowsCellularAccess = NO;
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
*/
@end
NSURLSession的简单
最新推荐文章于 2021-08-08 03:03:34 发布