iOS开发 - 同步异步下载

同步请求

1.
//这种方式请求和响应都包含在内
NSData * data =[NSData dataWithContentsOfURL:url];

2.
//请求类
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:str]];
//响应类
NSURLResponse * response = nil;
//NSError 报错类
NSError * error = nil;
//发送请求
NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//发送请求成功 服务器会给我们发响应 response/报错信息 error

异步请求

1.GET请求
//GET请求 没有设置请求方式 默认是get请求
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:path] cachePolicy:0 timeoutInterval:10];
//发送异步请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
//解析过程
id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSLog(@”%@”,obj);
}];
//queue 队列/线程
//程序运行会有一个主线程 所有UI的操作都是主线程在做
//[NSOperationQueue mainQueue] 主线程
//completionHandler 返回数据 响应成功 通过block把数据返回回来

2.NSURLConnection Block
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
//设置请求方式
request.HTTPMethod = @”POST”;
//参数放到请求体里面
NSString * str = @”page=1&number=20”;
request.HTTPBody = [str dataUsingEncoding:NSUTF8StringEncoding];

//发送请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    //解析
    id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
}];

3.NSURLConnection 协议代理

NSURL * url = [NSURL URLWithString:str];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
//发送请求
[NSURLConnection connectionWithRequest:request delegate:self];


*******************协议方法*************

//发送请求成功 服务器响应 会调用这个方法
-(void)connection:(NSURLConnection )connection didReceiveResponse:(NSURLResponse )response{
NSLog(@”%@”,response);
NSHTTPURLResponse * urlResponse = (id)response;
if (urlResponse.statusCode == 200) {
self.muData = [[NSMutableData alloc] init];
}

//清空可变data
self.muData.length = 0;

}
//接收数据会调用这个方法 接收数据是一段一段的 这个方法会被反复调用 数据越大调用次数越多
-(void)connection:(NSURLConnection )connection didReceiveData:(NSData )data{

NSLog(@"接收到数据");
[self.muData appendData:data];

}
//接收数据完毕
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{

id obj = [NSJSONSerialization JSONObjectWithData:self.muData options:NSJSONReadingMutableContainers error:nil];

NSLog(@"%@",obj);

}
//错误
-(void)connection:(NSURLConnection )connection didFailWithError:(NSError )error{

NSLog(@"%@",error);

}

4.NSURLSession

NSURLSession的基本设置

NSURLRequest *request = [NSURLRequest requestWithURL:url];
//配置对象
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
//会话对象
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];

//普通任务
NSURLSessionDataTask * task = [session dataTaskWithRequest:request];
[task resume];

NSURLSession的协议方法

//响应成功 调用该方法
-(void)URLSession:(NSURLSession )session dataTask:(NSURLSessionDataTask )dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
NSLog(@”%@”,response);

//清空可变data容器
self.muData.length = 0;

//****这个block必须要调用****
completionHandler(NSURLSessionResponseAllow);
/*
    NSURLSessionResponseCancel = 0,   //取消接收数据
    NSURLSessionResponseAllow = 1,      //继续下载数据
    NSURLSessionResponseBecomeDownload = 2,     //把数据变成下载
    NSURLSessionResponseBecomeStream    //变成数据流
*/

}

//这个方法会被多次调用 接收数据会调用这个方法 数据返回的时候是一段一段的
-(void)URLSession:(NSURLSession )session dataTask:(NSURLSessionDataTask )dataTask didReceiveData:(NSData *)data{
//拼接数据
[self.muData appendData:data];
}
//不管下载成功或失败 都会调用这个方法
-(void)URLSession:(NSURLSession )session task:(NSURLSessionTask )task didCompleteWithError:(NSError *)error{

if (error) {
    NSLog(@"%@",error);
}
else{
    //下载成功 解析数据
    id obj = [NSJSONSerialization JSONObjectWithData:self.muData options:NSJSONReadingMutableContainers error:nil];
    NSLog(@"%@",obj);
}

}

NSURLSession Block写法

1.普通任务

//创建session(会话)对象
//创建的是单例对象 这种方式和使用NSURLConnection是一样的
NSURLSession * session = [NSURLSession sharedSession];

//NSURLSessionDataTask普通下载
NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //data我们需要的数据 response响应对象 error报错信息
    //解析数据
}];
//completionHandler 响应成功 数据回调的时候会调用这个方法
//执行任务 发送请求
[task resume];

2.普通任务

NSURLRequest *request = [NSURLRequest requestWithURL:url];
//  NSURLSessionConfiguration工作配置
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
//defaultSessionConfiguration 默认配置
//ephemeralSessionConfiguration 瞬时会话模式 不考虑缓存配置
//backgroundSessionConfigurationWithIdentifier:@"id" 后台配置

//参数 标识符 可以区分多个后台多个下载任务
//设置超时时间
config.timeoutIntervalForRequest = 10.0;
//允许使用移动蜂窝网络
config.allowsCellularAccess = YES;
//根据电量选择网络,电量充足会选择合适的网络
config.discretionary = YES;

//创建会话对象
NSURLSession * session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];

    NSLog(@"%@",obj);
}];
//执行
[task resume];

3.数据下载

NSURLRequest * request = [NSURLRequest requestWithURL:url];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];  
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

NSURLSessionDownloadTask * downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
    //下载的数据会存放到默认缓存的位置 任务一结束 缓存被清空
    NSString * str = NSHomeDirectory();
    //存放路径+文件名
    NSString * path = [str stringByAppendingPathComponent:@"library/text.txt"];

    //把本地路径转成NSURL对象
    NSURL * url1 = [NSURL fileURLWithPath:path];
    //将数据写在本地的路径下

}];
//执行下载任务
[downloadTask resume];

4.数据上传

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];  
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:@""]];   
NSURLSession * session = [NSURLSession sessionWithConfiguration:config];

//第二个参数(fromData) 为需要上传的数据
NSURLSessionUploadTask * task = [session uploadTaskWithRequest:request fromData:nil completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //返回的第一个参数 是否上传成功 用户id信息等 即服务器返回的数据  
    //解析

}];
//执行任务
[task resume];

5.普通下载

NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:URL]];
NSProgress * progress = nil;
NSURLSessionDownloadTask * task =
[manager downloadTaskWithRequest:request progress:&progress destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
    // destination 这个block需要返回一个NSURL 本地存储文件的url地址
    // 参数 targetPath 缓存url
    //正常情况下 可需要把文件放到沙盒目录下
    NSString * path = @"/Users/qianfeng/Desktop/QQ.dmg";
    //fileURLWithPath 拿到的是本地URL的路径
    return [NSURL fileURLWithPath:path];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    //任务完成的时候调用
    NSLog(@"%@ %@",error,[NSString stringWithContentsOfURL:filePath encoding:NSUTF8StringEncoding error:nil]);
}];
//观察进度
//NSProgress的属性--fractionCompleted 完成进度
[progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:nil];
[task resume];

6.断点续传 Demo

功能实现: 点击开始按钮 开始下载 ,点击暂停,停止下载 再次点击开始的时候继续下载。当程序中断退出再次进入的时候,可以继续上次的内容下载。

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIButton *startBtn;
@property (weak, nonatomic) IBOutlet UIButton *stopBtn;
@property (weak, nonatomic) IBOutlet UILabel *proLabel;
@property (weak, nonatomic) IBOutlet UIProgressView *progress;

@property (nonatomic,strong) NSURLSessionDataTask *task;

@property (nonatomic,assign) unsigned long long nowSize;//当前下载文件的大小 文件的字节数
@property (nonatomic,assign) unsigned long long fileSize;//总的文件的大小/字节数

@property (nonatomic,strong) NSFileHandle * handle;

@end

@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];
    self.nowSize = 0;

    [self addObserver:self forKeyPath:@”nowSize” options:NSKeyValueObservingOptionNew context:nil];
    //读取本地总的字节数
    self.fileSize = [[[NSUserDefaults standardUserDefaults] objectForKey:@”fileSize”] integerValue];
    //当前已下载的字节数
    //NSFileManager 是一个单例对象
    NSFileManager * manager = [NSFileManager defaultManager];
    //fileExistsAtPath 当前路径下的文件是否存在
    if (![manager fileExistsAtPath:@”/Users/qianfeng/Desktop/QQ1.dmg”]) {
    [manager createFileAtPath:@”/Users/qianfeng/Desktop/QQ1.dmg” contents:nil attributes:nil];
    }
    NSDictionary * dic = [manager attributesOfItemAtPath:@”/Users/qianfeng/Desktop/QQ1.dmg” error:nil];
    //当前已经下载的字节数
    self.nowSize = [dic[@”NSFileSize”] integerValue];
    }

  • (IBAction)onClickStart:(id)sender {

    NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];

    NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]];

    //设置请求头—RANGE
    [request setValue:[NSString stringWithFormat:@”bytes=%lld-“,self.nowSize] forHTTPHeaderField:@”RANGE”];

    self.task = [session dataTaskWithRequest:request];

    [self.task resume];

    //开始按钮停止点击功能
    [sender setEnabled:NO];
    }

  • (IBAction)onClickStop:(id)sender {

    [self.startBtn setEnabled:YES];

    [self.task cancel];
    }

//请求成功 收到响应的时候
-(void)URLSession:(NSURLSession )session dataTask:(NSURLSessionDataTask )dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
//NSURLResponse 响应对象 NSHTTPURLResponse是NSURLResponse的子类 allHeaderFields拿到所有的响应头
NSDictionary * dic = [(NSHTTPURLResponse *)response allHeaderFields];
NSLog(@”收到数据…%@”,dic);

unsigned long long lastSize = [dic[@"Content-Length"] intValue];
//总大小
self.fileSize = lastSize + self.nowSize;

//将总的大小存在本地
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:@(self.fileSize) forKey:@"fileSize"];
[defaults synchronize];

//NSFileHandle写文件
self.handle = [NSFileHandle fileHandleForUpdatingAtPath:@"/Users/qianfeng/Desktop/QQ1.dmg"];
//定位到文件尾部 每一次都是接着上一次写
[self.handle seekToEndOfFile];
//必须调用这个block
completionHandler(NSURLSessionResponseAllow);

}

//实时拿到数据
-(void)URLSession:(NSURLSession )session dataTask:(NSURLSessionDataTask )dataTask didReceiveData:(NSData *)data{
NSLog(@”拿到数据…”);
//计算当前下载的数据大小
self.nowSize += data.length;
//写文件
[self.handle writeData:data];
}

-(void)URLSession:(NSURLSession )session task:(NSURLSessionTask )task didCompleteWithError:(NSError *)error{
//关闭写文件
[self.handle closeFile];
if (error) {
self.startBtn.enabled = YES;
NSLog(@”%@”,error);
}
else{
NSLog(@”下载完成”);
}
}

//观察数据变化
-(void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void *)context{

float value = self.nowSize*1.0/self.fileSize;

self.progress.progress = value;

self.proLabel.text = [NSString stringWithFormat:@"%.2f%%",value*100];

}

你可能感兴趣的:(iOS开发 - 同步异步下载)