有了上一篇文章的铺垫直接上代码,下面是分析原理.
// ViewController.m // 大文件下载 // Created by apple on 15/11/11. // Copyright © 2015年 LDSmallCat. All rights reserved. #import "ViewController.h" #import "DACircularProgressView.h"//进度条的第三方框架 @interface ViewController ()<NSURLConnectionDataDelegate> //下载和暂停按钮 @property (weak, nonatomic) IBOutlet UIButton *button; //用来写数据的文件句柄对象 @property(nonatomic,strong) NSFileHandle *writeHandle; //文件的总大小.用已经下载的进度 除以 文件的总大小,做出进度条 @property(nonatomic,assign) long long totalLength; //当前已经写入的文件大小.已经下载的, @property(nonatomic,assign) long long currentLength; ///链接对象 @property (nonatomic, strong) NSURLConnection *conn; //进度条 @property(nonatomic,weak) DACircularProgressView * circleView; @end @implementation ViewController - (void)viewDidLoad{ [super viewDidLoad]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ NSLog(@"didFailWithError"); } //接收到响应就会调用 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ //下载完成后 再次点击的时候,如果为1就直接返回,不在下载,或弹框告诉用户已经存在, //需要将self.currentLength写入本地文件才能做到不会重复下载.就是说这个程序无法避免重复下载 if (self.currentLength) return; //数据保存的路径 NSString * caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSString * filepath = [caches stringByAppendingPathComponent:@"download2.mp4"]; //通过这个路径创建一个文件 到 沙盒中 NSFileManager * mgr = [NSFileManager defaultManager]; [mgr createFileAtPath:filepath contents:nil attributes:nil]; //创建一个用来写入文件数据的文件句柄 self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filepath]; //获取文件总大小 self.totalLength = response.expectedContentLength; NSLog(@"didReceiveResponse文件总大小%lld",self.totalLength); } //接受到数据就会调用,如果数据很大会被调用多次.边下边存储到沙盒,不会有内存问题 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ //移动到文件的最后面 [self.writeHandle seekToEndOfFile]; //数据写入沙盒 [self.writeHandle writeData:data]; //累计文件长度,通过循环不断增大这个值,在下面的方法中拿到这个值量化去下载任务 //比如这里第一次拿到300字节,下面请求下载0-300的任务,下次拼接后为1000,下面请求下载300-1000 //的任务, self.currentLength += data.length; self.circleView.progress = (double)self.currentLength / self.totalLength; //经过不断拼接,已经写入的数据, NSLog(@"didReceiveData 已经下载的数据%lld ",self.currentLength); } //下载完成后调用,做些处理工作 - (void)connectionDidFinishLoading:(NSURLConnection *)connection{ //变量归零 self.currentLength = 1; self.totalLength = 0; //关闭文佳 [self.writeHandle closeFile]; self.writeHandle = nil; } - (IBAction)downLoad:(UIButton *)sender{ //状态取反 sender.selected = ! sender.selected; //断点续传,断点下载 if(sender.selected){ //1.点击下载,创建URL,发送请求.url中不能有中文 NSURL * url = [NSURL URLWithString:@"http://localhost/dawenjianyasuo.zip"]; //2.请求 NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url]; self.currentLength = 0; //设置请求头.实现的要点在这里,此处的Rang属性实现了下载的控制,用self.currentLength //来保存已经下载了多少字节, NSString * range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength]; [request setValue:range forHTTPHeaderField:@"Range"]; //下载(创建完conn对象后,会自动发起一个异步请求) self.conn = [NSURLConnection connectionWithRequest:request delegate:self]; }else{//一旦点击暂停创建的request就会销毁,再次点击下载时需要重新创建. [self.conn cancel]; self.conn = nil; } } @end
整体流程:
原理会在下一篇文章中说明,
时间: 2024-10-06 22:08:26