ios开发网络学习三:NSURLConnection小文件大文件下载

Posted Hello_IOS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ios开发网络学习三:NSURLConnection小文件大文件下载相关的知识,希望对你有一定的参考价值。

一:小文件下载

#import "ViewController.h"

@interface ViewController ()<NSURLConnectionDataDelegate>
/** 注释 */
@property (nonatomic, strong) NSMutableData *fileData;
@property (nonatomic, assign) NSInteger totalSize;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end

@implementation ViewController

-(NSMutableData *)fileData
{
    if (_fileData == nil) {
        _fileData = [NSMutableData data];
    }
    return _fileData;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self download3];
}

//耗时操作[NSData dataWithContentsOfURL:url]
-(void)download1
{
    //1.url
    NSURL *url = [NSURL URLWithString:@"http://img5.imgtn.bdimg.com/it/u=1915764121,2488815998&fm=21&gp=0.jpg"];
    
    //2.下载二进制数据
   NSData *data = [NSData dataWithContentsOfURL:url];
    
    //3.转换
    UIImage *image = [UIImage imageWithData:data];
}

//1.无法监听进度
//2.内存飙升
-(void)download2
{
    //1.url
   // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"];

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    
    //2.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.发送请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
       
        //4.转换
//        UIImage *image = [UIImage imageWithData:data];
//        
//        self.imageView.image = image;
        //NSLog(@"%@",connectionError);
        
        //4.写数据到沙盒中
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.mp4"];
        [data writeToFile:fullPath atomically:YES];
    }];
}

//内存飙升
-(void)download3
{
    //1.url
    // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"];
    
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    
    //2.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.发送请求
    [[NSURLConnection alloc]initWithRequest:request delegate:self];
}

#pragma mark ----------------------
#pragma mark NSURLConnectionDataDelegate
/**
 *  1:当接收到服务器响应的时候调用:只调用一次
 *
 */
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"didReceiveResponse");
    
    //得到文件的总大小(本次请求的文件数据的总大小)
    self.totalSize = response.expectedContentLength;
}


/**
 *    2:当下载数据的时候调用,可能被调用多次:在此方法内部有时需要拼接data,也可以在此方法中获得下载的进度
 *
 */
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
   // NSLog(@"%zd",data.length);
    [self.fileData appendData:data];
    
    //进度=已经下载/文件的总大小
    NSLog(@"%f",1.0 * self.fileData.length /self.totalSize);
}

/**
 * 3:下载失败的时候的调用
 *
 */
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}

/**
 *    4:下载成功的时候调用
 *
 */
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"connectionDidFinishLoading");
    //4.写数据到沙盒中
    NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.mp4"];
    
    [self.fileData writeToFile:fullPath atomically:YES];
    NSLog(@"%@",fullPath);
}

/**
 *    三种方法的区别:1:耗时操作[NSData dataWithContentsOfURL:url]  2:sendAsynchronousRequest,无法监听进度  3:可以进行进度的监听,以及对下载完成后数据的处理
 */
@end

(1)第一种方式(NSData)

```objc

//使用NSDta直接加载网络上的url资源(不考虑线程)

-(void)dataDownload

{

    //1.确定资源路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

 

    //2.根据URL加载对应的资源

    NSData *data = [NSData dataWithContentsOfURL:url];

 

    //3.转换并显示数据

    UIImage *image = [UIImage imageWithData:data];

    self.imageView.image = image;

 

}

```

(2)第二种方式(NSURLConnection-sendAsync)

```objc

//使用NSURLConnection发送异步请求下载文件资源

-(void)connectDownload

{

    //1.确定请求路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

 

    //2.创建请求对象

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

 

    //3.使用NSURLConnection发送一个异步请求

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {

        //4.拿到并处理数据

        UIImage *image = [UIImage imageWithData:data];

        self.imageView.image = image;

 

    }];

 

}

```

(3)第三种方式(NSURLConnection-delegate)

```objc

//使用NSURLConnection设置代理发送异步请求的方式下载文件

-(void)connectionDelegateDownload

{

    //1.确定请求路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

 

    //2.创建请求对象

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

 

    //3.使用NSURLConnection设置代理并发送异步请求

    [NSURLConnection connectionWithRequest:request delegate:self];

 

}

 

#pragma mark--NSURLConnectionDataDelegate

 

//当接收到服务器响应的时候调用,该方法只会调用一次

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    //创建一个容器,用来接收服务器返回的数据

    self.fileData = [NSMutableData data];

 

    //获得当前要下载文件的总大小(通过响应头得到)

    NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

    self.totalLength = res.expectedContentLength;

    NSLog(@"%zd",self.totalLength);

 

    //拿到服务器端推荐的文件名称

    self.fileName = res.suggestedFilename;

 

}

//当接收到服务器返回的数据时会调用

//该方法可能会被调用多次

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

//    NSLog(@"%s",__func__);

 

    //拼接每次下载的数据

    [self.fileData appendData:data];

 

    //计算当前下载进度并刷新UI显示

    self.currentLength = self.fileData.length;

 

    NSLog(@"%f",1.0* self.currentLength/self.totalLength);

    self.progressView.progress = 1.0* self.currentLength/self.totalLength;

 

 

}

//当网络请求结束之后调用

-(void)connectionDidFinishLoading:(NSURLConnection *)connection

{

    //文件下载完毕把接受到的文件数据写入到沙盒中保存

 

    //1.确定要保存文件的全路径

    //caches文件夹路径

    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

 

    NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName];

 

    //2.写数据到文件中

    [self.fileData writeToFile:fullPath atomically:YES];

 

    NSLog(@"%@",fullPath);

}

 

//当请求失败的时候调用该方法

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

    NSLog(@"%s",__func__);

}

 

```

 二:大文件下载

#import "ViewController.h"

@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;

@property (nonatomic, assign) NSInteger totalSize;
@property (nonatomic, assign) NSInteger currentSize;
/** 文件句柄*/
@property (nonatomic, strong)NSFileHandle *handle;
/** 沙盒路径 */
@property (nonatomic, strong) NSString *fullPath;
@end

@implementation ViewController
/**
 * 1:大文件下载的时候,不断的拼接二进制数据,此时会导致内存的飙升,所以此时应该用文件句柄去写文件,创建一个空文件夹,创建文件句柄对象,将下载的文件一点一点拼接到空文件夹内。在文件下载完毕后,要关闭文件句柄,并设为nil空值
 *
 */
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self download3];
}

//内存飙升
-(void)download3
{
    //1.url
    // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"];
    
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    
    //2.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.发送请求
    [[NSURLConnection alloc]initWithRequest:request delegate:self];
}

#pragma mark ----------------------
#pragma mark NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"didReceiveResponse");
    
    //1.得到文件的总大小(本次请求的文件数据的总大小)
    self.totalSize = response.expectedContentLength;
    
    //2.写数据到沙盒中
    self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.mp4"];
    
    //3.创建一个空的文件
    [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
    
    //4.创建文件句柄(指针)
    self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //1.移动文件句柄到数据的末尾
    [self.handle seekToEndOfFile];
    
    //2.写数据
    [self.handle writeData:data];
    
    //3.获得进度
    self.currentSize += data.length;
    
    //进度=已经下载/文件的总大小
    NSLog(@"%f",1.0 *  self.currentSize/self.totalSize);
    self.progressView.progress = 1.0 *  self.currentSize/self.totalSize;
    //NSLog(@"%@",self.fullPath);
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //1.关闭文件句柄
    [self.handle closeFile];
    self.handle = nil;
    
    NSLog(@"connectionDidFinishLoading");
    NSLog(@"%@",self.fullPath);
}
@end

(1)第一种方式(NSData)

```objc

//使用NSDta直接加载网络上的url资源(不考虑线程)

-(void)dataDownload

{

    //1.确定资源路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

 

    //2.根据URL加载对应的资源

    NSData *data = [NSData dataWithContentsOfURL:url];

 

    //3.转换并显示数据

    UIImage *image = [UIImage imageWithData:data];

    self.imageView.image = image;

 

}

```

(2)第二种方式(NSURLConnection-sendAsync)

```objc

//使用NSURLConnection发送异步请求下载文件资源

-(void)connectDownload

{

    //1.确定请求路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

 

    //2.创建请求对象

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

 

    //3.使用NSURLConnection发送一个异步请求

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {

        //4.拿到并处理数据

        UIImage *image = [UIImage imageWithData:data];

        self.imageView.image = image;

 

    }];

 

}

```

(3)第三种方式(NSURLConnection-delegate)

```objc

//使用NSURLConnection设置代理发送异步请求的方式下载文件

-(void)connectionDelegateDownload

{

    //1.确定请求路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

 

    //2.创建请求对象

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

 

    //3.使用NSURLConnection设置代理并发送异步请求

    [NSURLConnection connectionWithRequest:request delegate:self];

 

}

 

#pragma mark--NSURLConnectionDataDelegate

 

//当接收到服务器响应的时候调用,该方法只会调用一次

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    //创建一个容器,用来接收服务器返回的数据

    self.fileData = [NSMutableData data];

 

    //获得当前要下载文件的总大小(通过响应头得到)

    NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

    self.totalLength = res.expectedContentLength;

    NSLog(@"%zd",self.totalLength);

 

    //拿到服务器端推荐的文件名称

    self.fileName = res.suggestedFilename;

 

}

//当接收到服务器返回的数据时会调用

//该方法可能会被调用多次

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

//    NSLog(@"%s",__func__);

 

    //拼接每次下载的数据

    [self.fileData appendData:data];

 

    //计算当前下载进度并刷新UI显示

    self.currentLength = self.fileData.length;

 

    NSLog(@"%f",1.0* self.currentLength/self.totalLength);

    self.progressView.progress = 1.0* self.currentLength/self.totalLength;

 

 

}

//当网络请求结束之后调用

-(void)connectionDidFinishLoading:(NSURLConnection *)connection

{

    //文件下载完毕把接受到的文件数据写入到沙盒中保存

 

    //1.确定要保存文件的全路径

    //caches文件夹路径

    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

 

    NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName];

 

    //2.写数据到文件中

    [self.fileData writeToFile:fullPath atomically:YES];

 

    NSLog(@"%@",fullPath);

}

 

//当请求失败的时候调用该方法

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

    NSLog(@"%s",__func__);

}

 

```

#####5.0  大文件的下载

 

(1)实现思路

 

    边接收数据边写文件以解决内存越来越大的问题

(2)核心代码

```objc

 

//当接收到服务器响应的时候调用,该方法只会调用一次

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    //0.获得当前要下载文件的总大小(通过响应头得到)

    NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

    self.totalLength = res.expectedContentLength;

    NSLog(@"%zd",self.totalLength);

 

    //创建一个新的文件,用来当接收到服务器返回数据的时候往该文件中写入数据

    //1.获取文件管理者

    NSFileManager *manager = [NSFileManager defaultManager];

 

    //2.拼接文件的全路径

    //caches文件夹路径

    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

 

    NSString *fullPath = [caches stringByAppendingPathComponent:res.suggestedFilename];

    self.fullPath  = fullPath;

    //3.创建一个空的文件

    [manager createFileAtPath:fullPath contents:nil attributes:nil];

 

}

//当接收到服务器返回的数据时会调用

//该方法可能会被调用多次

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

 

    //1.创建一个用来向文件中写数据的文件句柄

    //注意当下载完成之后,该文件句柄需要关闭,调用closeFile方法

    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];

 

    //2.设置写数据的位置(追加)

    [handle seekToEndOfFile];

 

    //3.写数据

    [handle writeData:data];

 

    //4.计算当前文件的下载进度

    self.currentLength += data.length;

 

    NSLog(@"%f",1.0* self.currentLength/self.totalLength);

    self.progressView.progress = 1.0* self.currentLength/self.totalLength;

}

```

 

以上是关于ios开发网络学习三:NSURLConnection小文件大文件下载的主要内容,如果未能解决你的问题,请参考以下文章

处理 API 错误与网络错误

iOS学习——Socket

iOS开发学习笔记(OC语言)——网络请求

ios开发网络学习六:设置队列请求与RunLoop

如何学习python

ios开发网络学习AFN框架的使用一:get和post请求