首页 > 代码库 > iOS开发网络篇—文件下载(五·下载功能的封装)
iOS开发网络篇—文件下载(五·下载功能的封装)
iOS开发网络篇—文件下载(五·下载功能的封装)
一、简单说明
在前面几篇文章介绍下载代码的基础上,此文分析对下载功能进行封装。
通过之前的代码,我们发现仅仅是下载一个文件就需要写很长的代码,那么如果要下载多个文件,就需要写多份代码。在这里,我们把下载一个文件的代码进行封装。控制器只需要知道,下载哪个文件,下载到哪个路径就可以了。
在对下载的功能进行封装后,添加一个文件下载器,一个文件下载器只下载一个文件,封装后如果要下载多个文件的话,那么只需要创建多个文件下载器对象就可以进行控制和下载了。
二、代码示例
1.代码:
新建一个类,让其继承自NSObject类,一个文件下载器只下载一个文件。
自定义类的头文件代码:
1 // 2 // YYfileDownloader.h 3 // 4 // 5 // Created by apple on 14-7-1. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h>10 11 @interface YYfileDownloader : NSObject12 //下载的远程url(连接到服务器的路径)13 @property(nonatomic,strong)NSString *url;14 //下载后的存储路径(文件下载到什么地方)15 @property(nonatomic,strong)NSString *destPath;16 //是否正在下载(只有下载器内部清楚)17 @property(nonatomic,readonly,getter = isDownloading)BOOL Downloading;18 //用来监听下载进度19 @property(nonatomic,copy)void (^progressHandler)(double progress);20 //用来监听下载完成21 @property(nonatomic,copy)void (^completionHandler)();22 //用来监听下载错误23 @property(nonatomic,copy)void(^failureHandler)(NSError *error);24 -(void)pause;25 -(void)start;26 @end
自定义类的实现代码:
1 // 2 // YYfileDownloader.m 3 // 4 // 5 // Created by apple on 14-7-1. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYfileDownloader.h" 10 11 @interface YYfileDownloader ()<NSURLConnectionDataDelegate> 12 //请求对象 13 @property(nonatomic,strong)NSURLConnection *cnnt; 14 //文件句柄 15 @property(nonatomic,strong)NSFileHandle *writeHandle; 16 //当前获取到的数据长度 17 @property(nonatomic,assign)long long currentLength; 18 //完整数据长度 19 @property(nonatomic,assign)long long sumLength; 20 21 @end 22 @implementation YYfileDownloader 23 //开始下载 24 -(void)start 25 { 26 _Downloading=YES; 27 28 //创建一个请求 29 NSURL *URL=[NSURL URLWithString:self.url]; 30 NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:URL]; 31 32 //设置请求头信息 33 //self.currentLength字节部分重新开始读取 34 NSString *value=http://www.mamicode.com/[NSString stringWithFormat:@"bytes=%lld-",self.currentLength]; 35 [request setValue:value forHTTPHeaderField:@"Range"]; 36 37 //发送请求(使用代理的方式) 38 self.cnnt=[NSURLConnection connectionWithRequest:request delegate:self]; 39 40 } 41 42 //暂停下载 43 -(void)pause 44 { 45 _Downloading=NO; 46 //取消发送请求 47 [self.cnnt cancel]; 48 self.cnnt=nil; 49 } 50 51 #pragma mark- NSURLConnectionDataDelegate代理方法 52 /* 53 *当接收到服务器的响应(连通了服务器)时会调用 54 */ 55 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 56 { 57 #warning 判断是否是第一次连接 58 if (self.sumLength) return; 59 60 //1.创建文件存数路径 61 NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 62 NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"]; 63 64 65 66 //2.创建一个空的文件,到沙盒中 67 NSFileManager *mgr=[NSFileManager defaultManager]; 68 //刚创建完毕的大小是o字节 69 [mgr createFileAtPath:filePath contents:nil attributes:nil]; 70 71 //3.创建写数据的文件句柄 72 self.writeHandle=[NSFileHandle fileHandleForWritingAtPath:filePath]; 73 74 //4.获取完整的文件长度 75 self.sumLength=response.expectedContentLength; 76 } 77 78 /* 79 *当接收到服务器的数据时会调用(可能会被调用多次,每次只传递部分数据) 80 */ 81 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 82 { 83 //累加接收到的数据长度 84 self.currentLength+=data.length; 85 //计算进度值 86 double progress=(double)self.currentLength/self.sumLength; 87 // self.progress.progress=progress; 88 if (self.progressHandler) {//传递进度值给block 89 self.progressHandler(progress); 90 91 //相当于在此处调用了下面的代码 92 // ^(double progress) 93 // { 94 // //把进度的值,传递到控制器中进度条,以进行显示 95 // vc.progress.progress=progress; 96 // }; 97 } 98 99 100 //一点一点接收数据。101 NSLog(@"接收到服务器的数据!---%d",data.length);102 //把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)103 //移动到文件的尾部104 [self.writeHandle seekToEndOfFile];105 //从当前移动的位置,写入数据106 [self.writeHandle writeData:data];107 }108 109 /*110 *当服务器的数据加载完毕时就会调用111 */112 -(void)connectionDidFinishLoading:(NSURLConnection *)connection113 {114 NSLog(@"下载完毕----%lld",self.sumLength);115 //关闭连接,不再输入数据在文件中116 [self.writeHandle closeFile];117 self.writeHandle=nil;118 119 //清空进度值120 self.currentLength=0;121 self.sumLength=0;122 123 if (self.completionHandler) {//下载完成通知控制器124 self.completionHandler();125 //相当于下面的代码126 // ^{127 // NSLog(@"下载完成");128 // [self.btn setTitle:@"下载已经完成" forState:UIControlStateNormal];129 // }130 }131 132 }133 /*134 *请求错误(失败)的时候调用(请求超时\断网\没有网\,一般指客户端错误)135 */136 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error137 {138 if (self.failureHandler) {//通知控制器,下载出错139 self.failureHandler(error);140 //相当于调用了下面的代码141 // ^{142 // NSLog(@"下载错误!");143 // }144 }145 }146 147 @end
主控制器代码:
1 // 2 // YYViewController.m 3 // 01-文件的下载(不合理) 4 // 5 // Created by apple on 14-6-30. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h"10 #import "YYfileDownloader.h"11 12 @interface YYViewController ()13 14 @property(nonatomic,strong)YYfileDownloader *fileDownloader;15 @property (weak, nonatomic) IBOutlet UIButton *btn;16 @property (weak, nonatomic) IBOutlet UIProgressView *progress;17 @end18 19 @implementation YYViewController20 21 - (void)viewDidLoad22 {23 [super viewDidLoad];24 }25 26 #pragma mark-懒加载27 -(YYfileDownloader *)fileDownloader28 {29 if (_fileDownloader==nil) {30 _fileDownloader=[[YYfileDownloader alloc]init];31 //设置文件下载路径32 _fileDownloader.url=@"http://192.168.1.53:8080/MJServer/resources/video.zip";33 34 //设置文件保存路径35 NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];36 NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];37 _fileDownloader.destPath=filePath;38 39 //获取10的真实类型,把它作为a的类型40 // typeof(10) a = 20; // int a = 20;41 __weak typeof(self) vc=self;42 _fileDownloader.progressHandler=^(double progress)43 {44 vc.progress.progress=progress;45 NSLog(@"%f",progress);46 };47 _fileDownloader.completionHandler=^{48 NSLog(@"下载完成");49 [vc.btn setTitle:@"下载已经完成" forState:UIControlStateNormal];50 };51 _fileDownloader.failureHandler=^(NSError *error){52 NSLog(@"下载错误!%@",error);53 };54 }55 return _fileDownloader;56 }57 58 //点击下载按钮,处理操作59 - (IBAction)star {60 if (self.fileDownloader.isDownloading) {//如果正在下载,那么调用方法暂停61 [self.fileDownloader pause];62 [self.btn setTitle:@"暂停" forState:UIControlStateNormal];63 }else//如果没有正在下载,那么调用下载方法64 {65 [self.fileDownloader start];66 [self.btn setTitle:@"下载" forState:UIControlStateNormal];67 }68 }69 70 @end
2.代码说明
要在控制器中拿到下载的进度,可以使用代理,也可以使用block,这里使用block来进行实现。
给下载器传递一个下载进度的block,每隔一段时间,下载器就调用一次该block,然后把进度信息传递给外部的进度条进行显示。
/* *当接收到服务器的数据时会调用(可能会被调用多次,每次只传递部分数据) */-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ //累加接收到的数据长度 self.currentLength+=data.length; //计算进度值 double progress=(double)self.currentLength/self.sumLength;// self.progress.progress=progress; if (self.progressHandler) {//传递进度值给block self.progressHandler(progress); //相当于在此处调用了下面的代码// ^(double progress)// {// //把进度的值,传递到控制器中进度条,以进行显示// vc.progress.progress=progress;// }; }
在控制器中对进度值进行监听:
_fileDownloader.progressHandler=^(double progress) { vc.progress.progress=progress; NSLog(@"%f",progress); };
控制器想监听下载器的下载进度,控制器想监听下载器的下载完毕,控制器想监听下载器的下载失败等都可以使用block的方式进行。
打印查看:
三、补充
在IOS开发中,有的时候我们需要在已经存在的旧项目基础上,进行改进,下面说明怎么更改项目及文件的名称。
(1)打开项目后,点击修改项目的名称。
(2)修改完之后,点击回车,弹出下面的窗口。
(3)在导航栏上,如图点击。
(4)修改名称,之后点击OK。
(5)修改剩下的两个文件的名称。
至此,已经完成了所有的修改。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。