iOS进阶_NSURLSession(一.NSURLSession下载)

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的断点续传与代理队列及强引用

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/80390070