iOS开发——下载器的功能基本实现
今天,做了一个下载器的Demo,即从本地配置的Apache服务器上,下载指定的文件。这次,我们下载服务器根目录下的html.mp4文件。
按照惯例,我们先创建一个URL对象和请求。
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/html.mp4"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
这里有两点需要注意,第一,这个url的字符串是全英文的,如果在字符串中出现了中文,我们就不能直接调用URLWithString:这个方法,而是要先将url字符串存入一个字符串对象中,再将这个字符串通过
[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
方法才可以,否则无法正常请求。
由于是下载操作,我们就需要用到NSURLConnection的代理方法来实现,前提是先创建连接对象和对象的代理。
//建立连接,立即执行
[NSURLConnection connectionWithRequest:request delegate:self];
现在问题来了,代理不止一个可选,<NSURLConnectionDownloadDelegate>和<NSURLConnectionDataDelegate>,初次接触,本能地选择了第一个代理(因为从名字来看,第一个最像)。如果您的想法和我一样,那就错了,第一个代理中的方法实现后,确实可以获得数据,但是不知道数据存在了哪里,并不是我们指定的路径,您可以尝试一下。
好,经过第一次的失败,我们选择第二个代理,进入头文件,我们看到了四个方法:
//获得响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
//获取数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
//断开连接
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
//发生错误
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
我们可以清楚地了解每个方法的作用,您有兴趣可以打印下每个方法的参数瞧一瞧。
这里需要补充的是,我们加了几个属性
/// 文件下载流
@property (strong, nonatomic) NSOutputStream *fileStream;
/// 记录文件总长度
@property (assign, nonatomic) long long fileLength;
/// 文件当前长度
@property (assign, nonatomic) long long currentFileLength;
关于NSOutputStream,还有一个NSFileHandle可以和他进行比较,只是后者会造成文件被重复追加。因此,我们选择前者。根据类名我们可以推断出应该还有一个NSInputStream,没错,一个下载流,一个上传流。
第一步。在获得响应的方法中,我们从response参数里获得文件的总长度,并且置当前已经下载的文件长度是0,开启一个保存到指定路径的下载流,这里我们保存到桌面。
//获得响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.fileLength = response.expectedContentLength;
//当前文件长度置零
self.currentFileLength = ;
self.fileStream = [[NSOutputStream alloc] initToFileAtPath:@"/Users/xxx/Desktop/html.mp4" append:YES];
[self.fileStream open];
}
第二步。我们获得了数据,如果您在这个方法中打印数据,您就会发现当文件够大(几M就行)时,这个方法会被调用多次,也就是说,分多次获取数据。所以我们在这个方法中拼接数据,同时也要避免数据拼接后造成占用过多内存。我们累加已下载的数据的长度,计算已下载的百分比,并写入数据流中。在计算百分比时,记得转换类型哦,不然结果都是0,除了最后一个是1。
//获取数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// NSLog(@"did receive:%@",data);
self.currentFileLength += data.length;
float progressPercent = (float)self.currentFileLength / self.fileLength;
NSLog(@"have downloaded: %f", progressPercent);
[self.fileStream write:data.bytes maxLength:data.length];
}
最后一步。实际上是两个方法,一个是下载完成调用,一个是下载失败调用。有一点需要注意,无论下载成功或失败,都需要把文件输出流关闭。
//断开连接
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"连接结束");
[self.fileStream close];
} //发生错误
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%@",error);
[self.fileStream close];
}
这只是下载功能的基本实现,接下来会添加下载进度条,并对下载操作进行跟多优化(多线程,断点续传等),最后会对下载操作进行封装。
感谢阅读!
iOS开发——下载器的功能基本实现的更多相关文章
- 深入理解iOS开发中的BitCode功能
前言 做iOS开发的朋友们都知道,目前最新的Xcode7,新建项目默认就打开了bitcode设置.而且大部分开发者都被这个突如其来的bitcode功能给坑过导致项目编译失败,而这些因为bitcode而 ...
- iOS开发中WiFi相关功能总结
http://www.cocoachina.com/ios/20160715/17022.html 投稿文章,作者:Haley_Wong(简书) 查漏补缺集是自己曾经做过相关的功能,但是重做相关功能或 ...
- iOS开发——高级技术&广告功能的实现
广告功能的实现 iPhone/iPad的程序,即使是Free的版本,也可以通过广告给我们带来收入.前提是你的程序足够吸引人,有足够的下载量.这里,我将介绍一下程序中集成广告的方法.主要有两种广告iAd ...
- iOS开发——高级技术&密码锁功能的实现
密码锁功能的实现 一个ios手势密码功能实现 ipad/iphone 都可以用 没有使用图片,里面可以通过view自己添加 keychain做的数据持久化,利用苹果官方KeychainItemWrap ...
- IOS开发 二维码功能的实现
原帖地址:http://yul100887.blog.163.com/blog/static/20033613520121020611299/ 如今二维码随处可见,无论是实物商品还是各种礼券都少不了二 ...
- IOS开发-项目实战-点赞功能的实现
实现思路: 1.每一条新闻就是一个cell,在cell上添加点赞按钮. 2.让cell的控制器成为自定义cell的代理,将点击了哪一个cell放在代理方法中传出去. 3.并将这条新闻的ID和当前用户的 ...
- iOS开发——高级技术&通讯录功能的实现
通讯录功能的实现 iOS 提供了对通讯录操作的组建,其中一个是直接操作通讯录,另一个是调用通讯录的 UI 组建.实现方法如下: 添加AddressBook.framework到工程中. 代码实现: 1 ...
- iOS开发——高级技术&支付宝功能的实现
支付宝功能的实现 现在不少app内都集成了支付宝功能 使用支付宝进行一个完整的支付功能,大致有以下步骤: 1>先与支付宝签约,获得商户ID(partner)和账号ID(seller) (这个 ...
- iOS开发下载文件速度计算
当我们写下载界面的时候,需要向用户展示每秒下载多少KB,这个时候就需要计算速度.如下: 我用的是AFNetworking来做下载的,我们拿AFHTTPRequestOperation来举列,AFHTT ...
随机推荐
- SDP(7):Cassandra- Cassandra-Engine:Streaming
akka在alpakka工具包里提供了对cassandra数据库的streaming功能.简单来讲就是用一个CQL-statement读取cassandra数据并产生akka-stream的Sourc ...
- bzoj 2288 【POJ Challenge】生日礼物 双向链表+堆优化
2288: [POJ Challenge]生日礼物 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1003 Solved: 317[Submit][ ...
- Yii2中JSONP跨域问题的解决
Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据. 为什么我们从不同的域(网站)访问数据需 ...
- C语言_结构体的4种定义初始化方式及案例
结构体是一种构造数据类型 (构造数据类型:数组类型.结构体类型(struct).共用体类型(union)).用途:把不同类型的数据组合成一个整体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一 ...
- xBIM WeXplorer 设置模型颜色
目录 基础 xBIM WeXplorer 简要介绍 xBIM WeXplorer xViewer 基本应用 xBIM WeXplorer xViewer 浏览器检查 xBIM WeXplorer xV ...
- 百度前端技术学院js任务三
任务地址:http://ife.baidu.com/course/detail/id/98 代码: <!DOCTYPE> <html> <head> <met ...
- EL表达式判断不能为空
前几天在做一个网站的时候遇到一个问题,要判断一个在request或者session域里面的对象是否为空,利用EL表达式,正常思维就是用 <c:if test="${* != null} ...
- 【SSH框架】系列之 Spring 整合 Hibernate 框架
1.SSH 三大框架整合原理 Spring 与 Struts2 的整合就是将 Action 对象交给 Spring 容器来负责创建. Spring 与 Hibernate 的整合就是将 Session ...
- Windows10系统故障检测你知道多少-上海IT33
Windows 10作为微软公司最新的一款操作系统,从使用的方便和界面的整洁上来说,固然是很好的,但是其因为隐私问题,致使很多人不惜一切代价想要远离Windows 10这款操作系统.尽管Windows ...
- 关于VS2013调试IIS应用源代码时无法进入断点的问题总结
调试无法进入断点 前言:今天再次遇到之前调试无法进入断点的问题,本来想不写呢觉得没什么只是又犯了同样的错误,但是我发现这个问题我分析起来还是挺费劲的,我仔细想了想原因, 是因为自己对之前的错误没有进行 ...