#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic, strong) NSMutableData *receiveData;
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
@property (weak, nonatomic) IBOutlet UILabel *progressLabel;
@end
// ViewController.m
// UIGJ04-02
//
// Created by imac on 15/9/7.
// Copyright (c) 2015年 imac. All rights reserved.
//
#import "ViewController.h"
/*
下载性能优化
使用一个缓冲Data存储下载数据,当缓冲的数据>500kb,将此缓冲数据写入文件,并且清楚缓冲数据,以节约内存
*/
/*
断点续传的实现思路:
1. 暂停的时候,记录下载的暂停位置
2. 继续下载时,设置下载的起始位置
http协议的请求头的设置:
Range : bytes=0-499 表示头500个字节
Range : bytes=500-999 表示第二个500字节
Range : bytes=-500 表示最后500个字节
Range : bytes=500- 表示500字节以后的范围
Range : bytes=0-0,-1 第一个和最后一个字节
3. 续传写入文件时,总是从文件末尾追加写入文件
*/
@interface ViewController ()<NSURLConnectionDataDelegate>
{
double totalSize; //下载数据的总大小
double receiveTotal; //接收的数据大小
NSString *_filePath; //文件存储的路径
BOOL isDownLoad;//标识是否在下载
NSURLConnection *_connection; //网络请求对象
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"%@", NSHomeDirectory());
//取得下载数据的大小 userDefaults是一个单例
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
receiveTotal = [[userDefaults objectForKey:@"ReceivedTotal"] doubleValue];
totalSize = [[userDefaults objectForKey:@"TotalSize"] doubleValue];
//显示上一次下载的进度
if (totalSize > 0) {
CGFloat progress = receiveTotal / totalSize;
self.progressLabel.text = [NSString stringWithFormat:@"%.2f%%", progress * 100];
self.progressView.progress = progress;
}
}
- (IBAction)downLoadAction:(UIButton *)sender {
if (!isDownLoad) {
//1、 构建URL
NSURL *url = [NSURL URLWithString:@"http://free2.macx.cn:8182/tools/other4/iStatMenus511b17.dmg"];
//2、 构建Request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//设置断点续传
if (receiveTotal > 0) {
//设置继续下载的位置
NSString *value = [NSString stringWithFormat:@"bytes=%d-",(int)receiveTotal];
[request setValue:value forHTTPHeaderField:@"Range"];
}
//3、 发送异步请求
_connection = [NSURLConnection connectionWithRequest:request delegate:self];
isDownLoad = YES;
//获取字符串
NSString *urlStr = url.absoluteString;
//获取路径的最后一部分
NSString *fileName = [urlStr lastPathComponent];
//构建文件路径
_filePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@",fileName];
//创建文件
//判断文件是否存在,再创建
if (![[NSFileManager defaultManager] fileExistsAtPath:_filePath]) {
[[NSFileManager defaultManager] createFileAtPath:_filePath contents:nil attributes:nil];
}
}
}
- (IBAction)pauseAction:(UIButton *)sender {
//取消下载
[_connection cancel];
_connection = nil;
//将缓冲数据写入文件
[self appendFileData:self.receiveData];
//本地保存下载文件的大小 和 总文件的大小 生成的plist文件存放在当前文件路径下Library -- 》 Preferences 中
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@(receiveTotal) forKey:@"ReceivedTotal"];
[userDefaults setObject:@(totalSize) forKey:@"TotalSize"];
//将数据同步写入文件
[userDefaults synchronize];
isDownLoad = NO;
}
#pragma mark -NSURLConnectionDataDelegate
//服务器响应了
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
self.receiveData = [[NSMutableData alloc] init];
//判断总大小是否为0,为0,说明是从起始位置开始下载,需要获取总文件的大小
if (totalSize == 0) {
//获取所有响应头
NSDictionary *fields = response.allHeaderFields;
//获取数据的总大小
NSNumber *length = [fields objectForKey:@"Content-Length"];
totalSize = [length doubleValue];
NSLog(@"totalSize is %.2f", totalSize);
}
}
//接收数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// NSLog(@"%ld", data.length);
[self.receiveData appendData:data];
//已接收数据总大小 / 下载文件的总大小 = 进度
receiveTotal += data.length;
double progress = receiveTotal / totalSize;
//当前实在主线程中 刷新UI
self.progressView.progress = progress;
self.progressLabel.text = [NSString stringWithFormat:@"%.2f%%", progress * 100];
//判断缓冲的数据大小是否>500kB
if (self.receiveData.length > 500 * 1000) {
//往文件路径中写入数据
[self appendFileData:self.receiveData];
//清空
[self.receiveData setData:nil];
}
}
- (void)appendFileData:(NSData *)data
{
if (data.length == 0) {
return;
}
//使用NSFielHandle写文件,此文件必须已经创建
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:_filePath];
//将数据插入到写入点
[fileHandle seekToEndOfFile];
[fileHandle writeData:data];
//关闭文件,确保写入完成
[fileHandle closeFile];
}
//数据传输完成
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//将最后一个缓冲文件数据写入文件
if (self.receiveData.length < 500 * 1000) {
[self appendFileData:self.receiveData];
[self.receiveData setData:nil];
}
_progressLabel.text = @"下载完成";
isDownLoad = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end