iOS实战iOS-开发iOS Developer

iOS 网络文件下载之NSURLConnection

2016-08-31  本文已影响272人  小黑_Coder

iOS 网络文件下载之NSURLConnection

小文件的网络下载

NSData下载方式

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    imageView.center = self.view.center;
    [self.view addSubview:imageView];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://attach2.scimg.cn/forum/201503/17/172255yjcdki30xted033j.jpg"]];
        dispatch_async(dispatch_get_main_queue(), ^{
            
            imageView.image = [UIImage imageWithData:data];
        });
    });

NSURLConnection方式下载

NSURL* url = [NSURL URLWithString:@"http://attach2.scimg.cn/forum/201503/17/172255yjcdki30xted033j.jpg"];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

self.imageView.image = [UIImage imageWithData:data];
    }];

上面我们也提到了,因为图片比较小,所以我们不用涉及到断点续传,防止重复下载问题,但是我们如果下载一个蓝光高清呢?这个座位用户当然希望可以断点续存了,好如何处理好下载问题,着就是本篇博客重点讲解的内容

大文件的网络下载

NSURLConnection方式下载

//不用多说当然先是初始化一个NSURLConnection的实例了
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://download.xmcdn.com/group18/M01/BC/91/wKgJKlfAEN6wZgwhANQvLrUQ3Pg146.aac"]];
    _connection = [NSURLConnection connectionWithRequest:request delegate:self];
//此代理方法在请求接收到服务器响应的时候回调
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
//此代理方法在下载中会多次回调,每次传回一部分数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
//此代理方法在下载完成的时候回调
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
//首先我们是设置相关的属性
@property (nonatomic, strong) NSURLConnection *connection;          //NSURLConnection下载实例
@property (nonatomic, strong) UIView *progressView;                 //下载进度条
@property (nonatomic, strong) UILabel *progressLabel;               //显示进度百分比
@property (nonatomic, strong) NSMutableData *downloadData;          //下载的数据
@property (nonatomic, strong) NSFileHandle *fileHandle;             //用来操作数据的句柄
@property (nonatomic, assign) long long writtenDataLength;          //累计写入长度
@property (nonatomic, assign) long long totalwriteDataLength;       //共需要写入的长度

//收到服务器的响应时
//1.创建一个空的文件夹用来存储下载的文件
//2.并初始化用来操作数据的句柄
//3.记录需要文件的总长度
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:response.suggestedFilename];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager createFileAtPath:filePath contents:nil attributes:nil];
    _fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
    _writtenDataLength = 0;
    _totalwriteDataLength = response.expectedContentLength;
}

//收到服务器返回的数据
//1.将句柄移到文件的最尾端
//2.将此次返回的数据写入sandbox
//3.更新已经下载的长度
//4.刷新UI
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [_fileHandle seekToEndOfFile];
    [_fileHandle writeData:data];
    _writtenDataLength += data.length;
    _progressLabel.text = [NSString stringWithFormat:@"%.2f%%", (double)_writtenDataLength/(double)_totalwriteDataLength*100];
    _progressView.frame = CGRectMake(0, 0, ([UIScreen mainScreen].bounds.size.width-200)*_writtenDataLength/_totalwriteDataLength, 1);
}

//下载完成
//1.关闭文件夹
//2.销毁操作数据的句柄
//3.清空数据
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [_fileHandle closeFile];
    _fileHandle = nil;
    _writtenDataLength = 0;
    _totalwriteDataLength = 0;
}

NSURLConnection实现断点续传

//Range 可以指定每次从网络下载数据包的大小
bytes = 0 - 499                 //从0到499共500
bytes = 500 -                   //从500到结束
bytes = -500                    //最后500
bytes = 500 - 599, 800 - 899    //同时指定几个范围
    [sennder setTitle:@"Pause Download" forState:UIControlStateNormal];
    NSURL *url = [NSURL URLWithString:@"http://download.xmcdn.com/group18/M01/BC/91/wKgJKlfAEN6wZgwhANQvLrUQ3Pg146.aac"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSString *range = [NSString stringWithFormat:@"bytes=%lld-", _writtenDataLength];
    [request setValue:range forHTTPHeaderField:@"Range"];
    _connection = [NSURLConnection connectionWithRequest:request delegate:self];    
//收到服务器的响应时
//1.创建一个空的文件夹用来存储下载的文件
//2.并初始化用来操作数据的句柄
//3.记录需要文件的总长度
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:response.suggestedFilename];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:filePath])
    {
        NSData *writtenData = [NSData dataWithContentsOfFile:filePath];
        [fileManager createFileAtPath:filePath contents:writtenData attributes:nil];
        _writtenDataLength = writtenData.length;
    }
    _fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
    _totalwriteDataLength = response.expectedContentLength + _writtenDataLength;
}
NSURLConnection方式下载充分利用CPU性能
#pragma mark - NSURLConnectionDataDelegate
//1.获取要下载的总长度
//2.取消出发下载NSURLConnection
//3.将总长度分给4个NSURLConnection分别去下载
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    if ([connection isEqual:_connection])
    {
        _totalWriteDataLength = response.expectedContentLength;
        [_connection cancel];
        NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
        for (int i = 0; i < 4; i++)
        {
            NSString *filePath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%d", response.suggestedFilename, i]];
            NSFileManager *fileManager = [NSFileManager defaultManager];
            [fileManager createFileAtPath:filePath contents:nil attributes:nil];
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.1.1.dmg"]];
            NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", response.expectedContentLength/4*i, response.expectedContentLength/4*(i+1)];
            [request setValue:range forHTTPHeaderField:@"Range"];
            NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
            NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
            [_pathMArr addObject:filePath];
            [_connectionMArr addObject:connection];
            [_fileHandleMArr addObject:fileHandle];
        }
    }
}

//1.将句柄移到文件的最尾端
//2.将此次返回的数据写入sandbox
//3.更新已经下载的长度
//4.刷新UI
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSInteger index = [_connectionMArr indexOfObject:connection];
    NSFileHandle *fileHandle = [_fileHandleMArr objectAtIndex:index];
    [fileHandle seekToEndOfFile];
    [fileHandle writeData:data];
    switch (index) {
        case 0:
        {
            _writtenDataLength_1 += data.length;
            _progressLabel_1.text = [NSString stringWithFormat:@"%.2f%%", (double)_writtenDataLength_1/(double)_totalWriteDataLength*4*100];
            break;
        }
        case 1:
        {
            _writtenDataLength_2 += data.length;
            _progressLabel_2.text = [NSString stringWithFormat:@"%.2f%%", (double)_writtenDataLength_2/(double)_totalWriteDataLength*4*100];
            break;
        }
        case 2:
        {
            _writtenDataLength_3 += data.length;
            _progressLabel_3.text = [NSString stringWithFormat:@"%.2f%%", (double)_writtenDataLength_3/(double)_totalWriteDataLength*4*100];
            break;
        }
        case 3:
        {
            _writtenDataLength_4 += data.length;
            _progressLabel_4.text = [NSString stringWithFormat:@"%.2f%%", (double)_writtenDataLength_4/(double)_totalWriteDataLength*4*100];
            break;
        }
        default:
            break;
    }
    _totalWrittenDataLength = _writtenDataLength_1 + _writtenDataLength_2 + _writtenDataLength_3 + _writtenDataLength_4;
    _progressLabel.text = [NSString stringWithFormat:@"%.2f%%", (double)_totalWrittenDataLength/(double)_totalWriteDataLength*100];
}

//1.记录完成任务的个数
//2.判断总任务是否完成
//3.合并文件
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    _finishedCount++;
    NSInteger index = [_connectionMArr indexOfObject:connection];
    NSFileHandle *fileHandle = [_fileHandleMArr objectAtIndex:index];
    [fileHandle closeFile];
    fileHandle = nil;
    if (_finishedCount == 4)//将4个任务下载的文件合并成一个
    {
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSString *tmpPath = [_pathMArr objectAtIndex:index];
        NSString *filePath = [tmpPath substringToIndex:tmpPath.length];
        [fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
        NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
        for (int i = 0; i < 4; i++) {
            
            [fileHandle seekToEndOfFile];
            [fileHandle writeData:[NSData dataWithContentsOfFile:[_pathMArr objectAtIndex:i]]];
        }
        [fileHandle closeFile];
        fileHandle = nil;
        NSLog(@"%@", filePath);
        _progressLabel.text = @"下载完成";
    }
}
效果图

[相关代码]https://github.com/LHCoder2016/LHNSURLConnectionDownload.git
[欢迎讨论] huliuworld@yahoo.com

上一篇 下一篇

猜你喜欢

热点阅读