NSURLSession简介
在上一篇文章中,我们介绍了NSURLConnection做网络请求,坑很多。到目前为止开发者几乎不再使用NSURLConnection,而是改为更加便捷的方式,那就是NSURLSession。或者更多的是使用第三方框架,我们要使用第三方框架,也要了解它的使用原理,来更好的使用它!
NSURLSession出现在iOS7.0(15年),当时有个BUG,使用NSURLSession下载会使内存暴增,当时使用AFN也会出现这个问题,这属于苹果的BUG,所以在苹果解决BUG前,开发者还是部分要使用NSURLConnection。
-(void)session1{
//1.url
NSURL * url = [NSURL URLWithString:@"http://127.0.0.1/videos.json"];
//2.session -> 苹果提供了全局的单例,简化我们的开发
NSURLSession * session = [NSURLSession sharedSession];
//3.NSURLSessionDataTask -> 在NSRULSession 开发中,所有的任务都是由Session发起的
NSURLSessionDataTask * task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//反序列化
id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@",result);
} ];
//4.启动任务
[task resume];
}
整理合并session1
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//1.url
NSURL * url = [NSURL URLWithString:@"http://127.0.0.1/videos.json"];
//建立指定URL的数据任务
[self taskWithURL:url];
}
-(void)taskWithURL:(NSURL *)url{
//3.NSURLSessionDataTask -> 在NSRULSession 开发中,所有的任务都是由Session发起的
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//反序列化
id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@",result);
} ] resume];
}
这是一个简单的使用session做网络请求的例子,相对了NSURLConnection相当简单,且当做文件下载的时候,内存会相当稳定
NSURLSession下载
我们在前面的文章中介绍了MAC电脑搭建Apache服务器,在Sites文件夹中放置一个视频文件abc.wmv,通过NSURLConnection进行下载
访问http://localhost,我们可以进行查看,所有Apache服务器中的文件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSURL * url = [NSURL URLWithString:@"http://127.0.0.1/abc.wmv"];
[[[NSURLSession sharedSession]downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@",location);
}]resume];
}
如果不在回调方法中,不做任何处理,下载的文件会被删除
下载文件放在tmp里面的,系统会自动回收这块区域
这么设计的目的是:
- 通常从网络上下载文件,什么格式的文件最多 -> zip 文件最多,可以替用户节约流量
- 如果是zip包,下载之后,需要解压
- 解压之后,原始的zip文件就不需要了,系统会自动帮我们删除,这就是苹果设计tmp设计的初衷
文件解压缩
我们使用封装好的第三方SSZipArchive进行解压操作,扔到我们apche本地服务器一个压缩包文件sszip.zip,进行下载解压
// 静态库 - 每一个应用程序都会有一个副本
// 动态库 - 在系统中只有一个副本,只有苹果公司能够建立动态库,当然开发者也可以开发动态库,但是不允许上架!
#import "ViewController.h"
#import "SSZipArchive.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSURL * url = [NSURL URLWithString:@"http://127.0.0.1/sszip.zip"];
/*
如果不在回调方法中,不做任何处理,下载的文件会被删除
下载文件放在tmp里面的,系统会自动回收这块区域
这么设计的目的是:
- 通常从网络上下载文件,什么格式的文件最多 -> zip 文件最多,可以替用户节约流量
- 如果是zip包,下载之后,需要解压
- 解压之后,原始的zip文件就不需要了,系统会自动帮我们删除,这就是苹果设计tmp设计的初衷
*/
[[[NSURLSession sharedSession]downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@",location);
//下载结束,解压缩到目标路径
NSString * cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//解压缩
/* 只需要指定目标路径,而不需要指定目标文件
因为一个压缩包中可能有多个文件
*/
[SSZipArchive unzipFileAtPath:location.path toDestination:cachePath];
}]resume];
}
@end
NSURLSession下载进度监听
#import "ViewController.h"
@interface ViewController ()<NSURLSessionDownloadDelegate>
/** 全局的网络会话(Session),管理所有的网络任务 **/
@property(nonatomic,strong)NSURLSession * session;
@end
@implementation ViewController
-(NSURLSession *)session{
if (!_session) {
//config 提供了一个全局的网络环境配置,包括:身份验证,浏览器类型,cookie,缓存,超时...
NSURLSessionConfiguration * config =[NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
}
return _session;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSURL * url = [NSURL URLWithString:@"http://127.0.0.1/abc.wmv"];
NSLog(@"开始");
//如果需要下载进度,NSURLSession和NSURLConnection一样,都是使用代理
//NSURLSession的单例是全局的,是整个系统的,那么我们设置代理,不能用全局的进行设置
/*
如果要跟进下载进度,不能使用block回调的方式,否则不走代理
*/
// [[self.session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// NSLog(@"%@",location);
//
// }]resume];
[[self.session downloadTaskWithURL:url] resume];
}
#pragma mark - <NSURLSessionDownloadDelegate>
/*
iOS7.0,以下三个方法都是必须要实现的,到了iOS8.0只剩下下载完成是必须的
*/
/*1.下载完成方法*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSLog(@"完成 %@",location);
}
//2.下载进度
/**
1.session
2.downloadTask 调用代理方法的下载任务
3.bytesWritten 本次下载的字节数
4.bytesWritten 已经下载的字节数
5.totalBytesExpectedToWrite 期望下载的字节数 -> 文件总大小
*/
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
float progress = (float)totalBytesWritten / totalBytesExpectedToWrite ;
NSLog(@"%f",progress);
}
//3.下载续传数据
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
}
@end
自定义Progress
拖一个button进来,修改type为cusstom
创建一个继承自UIButton的WTProgressBtn的类
WTProgressBtn.h
#import <UIKit/UIKit.h>
@interface WTProgressBtn : UIButton
/** 进度0.0-1.0 **/
@property(nonatomic,assign)float progress;
@end
WTProgressBtn.m
#import "WTProgressBtn.h"
@implementation WTProgressBtn
- (void)setProgress:(float)progress{
_progress = progress;
//设置标题
[self setTitle:[NSString stringWithFormat:@"%.02f%%",_progress * 100] forState:(UIControlStateNormal)];
//刷新视图
[self setNeedsDisplay];
}
//rect self.bounds
/*
面试题:
写一个宏,myMIN(a,b) 返回最小值
写一个宏 myMIN3(a,b,c) 返回最小值
*/
#define myMIN(a,b) ((a) < (b))?(a):(b)
#define myMIN3(a,b,c) myMIN(myMIN(a,b),c)
//自己定义
- (void)drawRect:(CGRect)rect{
CGSize s = rect.size;
CGPoint center = CGPointMake(s.width * 0.5, s.height * 0.5);
CGFloat r = myMIN(s.height, s.width) * 0.5;
r -= 5;
CGFloat startAng = - M_PI_2;
CGFloat endAng = (float)(self.progress * 2 * M_PI + startAng);
/*
1.圆心
2.半径
3.起始角度
4.结束角度
5.顺时针
*/
UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:center radius:r startAngle:startAng endAngle:endAng clockwise:YES];
//设置线条宽度
path.lineWidth = 10.0;
path.lineCapStyle = kCGLineCapRound;
//设置颜色
[[UIColor yellowColor]setStroke];
//绘制路径
[path stroke];
}
@end
下一篇文章中,我们着重分析NSURLSession的断点续传与代理队列及强引用