iOS开发AFN使用二:AFN文件下载与文件上传

时间:2022-08-29 08:15:06
#import "ViewController.h"
#import "AFNetworking.h"

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self download];
}

-(void)download
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];
    
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //2.下载文件
    /*
     第一个参数:请求对象
     第二个参数:progress 进度回调 downloadProgress
     第三个参数:destination 回调(目标位置)
                有返回值
                targetPath:临时文件路径
                response:响应头信息
     第四个参数:completionHandler 下载完成之后的回调
                filePath:最终的文件路径
     */
    
    /*
     第一个参数:请求对象
     第二个参数:进度回调
     downloadProgress.completedUnitCount :已经下载的数据
     downloadProgress.totalUnitCount:数据的总大小
     第三个参数:destination回调,该block需要返回值(NSURL类型),告诉系统应该把文件剪切到什么地方
     targetPath:文件的临时保存路径tmp,随时可能被删除
     response:响应头信息
     第四个参数:completionHandler请求完成后回调
     response:响应头信息
     filePath:文件的保存路径,即destination回调的返回值
     error:错误信息
     */
    NSURLSessionDownloadTask *download = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        
        //监听下载进度
        //completedUnitCount 已经下载的数据大小
        //totalUnitCount     文件数据的中大小
        NSLog(@"%f",1.0 *downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
        
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        /**
         * 1:1:请求路径:NSUrl *url = [NSUrl urlWithString:path];从网络请求路径  2:把本地的file文件路径转成url,NSUrl *url = [NSURL fileURLWithPath:fullPath];
           2:返回值是一个下载文件的路径
         *
         */
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
        
        NSLog(@"targetPath:%@",targetPath);
        NSLog(@"fullPath:%@",fullPath);
        
        return [NSURL fileURLWithPath:fullPath];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        /**
         *filePath:下载后文件的保存路径
         */
        NSLog(@"%@",filePath);
    }];
    
    //3.执行Task
    [download resume];
}


@end

(2)使用AFN下载文件

```objc

-(void)download

{

    //1.创建会话管理者

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

 

 

    //2.创建请求对象

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_13.png"]];

 

    //3.创建下载Task

    /*

     第一个参数:请求对象

     第二个参数:进度回调

        downloadProgress.completedUnitCount :已经下载的数据

        downloadProgress.totalUnitCount:数据的总大小

     第三个参数:destination回调,该block需要返回值(NSURL类型),告诉系统应该把文件剪切到什么地方

        targetPath:文件的临时保存路径

        response:响应头信息

     第四个参数:completionHandler请求完成后回调

        response:响应头信息

        filePath:文件的保存路径,即destination回调的返回值

        error:错误信息

     */

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {

        NSLog(@"%f",1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);

 

    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {

 

        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];

        NSLog(@"%@\n%@",targetPath,fullPath);

        return [NSURL fileURLWithPath:fullPath];

 

    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {

        NSLog(@"%@",filePath);

    }];

 

    //4.执行Task

    [downloadTask resume];

}

```

 二:文件上传

#import "ViewController.h"
#import "AFNetworking.h"


#define Kboundary @"----WebKitFormBoundaryjv0UfA04ED44AhWx"

#define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self upload2];
}

//不推荐
-(void)upload
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    //2.1url
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    
    //2.2创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //2.3 设置请求方法
    request.HTTPMethod = @"POST";
    
    //2.4 设请求头信息
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
    
    //3.发送请求上传文件
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromData:[self getBodyData] progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount/ uploadProgress.totalUnitCount);
        
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
       
        NSLog(@"%@",responseObject);
    }];
    
    //4.执行task
    [uploadTask resume];
}

-(void)upload2
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
//    NSDictionary *dictM = @{}
    //2.发送post请求上传文件
    /*
     第一个参数:请求路径
     第二个参数:字典(非文件参数)
     第三个参数:constructingBodyWithBlock 处理要上传的文件数据
     第四个参数:进度回调
     第五个参数:成功回调 responseObject:响应体信息
     第六个参数:失败回调
     */
    [manager POST:@"http://120.25.226.186:32812/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        
        /**
         *    1:将image转换成NSData:可用 UIImagePNGRepresentation,也可用UIImageJPEGRepresentation
            2:data转换成image:UIImage *image = [UIImage imageWithData:data];
            3:url:1;网络路径:NSUrl urlWithString 2:NSUrl fileUrlWithStr:本地文件路径
            4:第三种方法:没有传fileName 和 mimeType,由AFN内部去自动设置,fileName截取的文件的url路径,mimeType由c语言内部去获取
         */
        UIImage *image = [UIImage imageNamed:@"Snip20160227_128"];
        NSData *imageData = UIImagePNGRepresentation(image);
        
        //使用formData来拼接数据
        /*
         第一个参数:二进制数据 要上传的文件参数
         第二个参数:服务器规定的
         第三个参数:该文件上传到服务器以什么名称保存
         */
        //[formData appendPartWithFileData:imageData name:@"file" fileName:@"xxxx.png" mimeType:@"image/png"];
        
        //[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/xiaomage/Desktop/Snip20160227_128.png"] name:@"file" fileName:@"123.png" mimeType:@"image/png" error:nil];
        
        [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/xiaomage/Desktop/Snip20160227_128.png"] name:@"file" error:nil];
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        
        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount/uploadProgress.totalUnitCount);
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"上传成功---%@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"上传失败---%@",error);
    }];
    
}
-(NSData *)getBodyData
{
    NSMutableData *fileData = [NSMutableData data];
    //5.1 文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
     Content-Type: image/png(MIMEType:大类型/小类型)
     空行
     文件参数
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //name:file 服务器规定的参数
    //filename:Snip20160225_341.png 文件保存到服务器上面的名称
    //Content-Type:文件的类型
    [fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"Sss.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    
    UIImage *image = [UIImage imageNamed:@"Snip20160227_128"];
    //UIImage --->NSData
    NSData *imageData = UIImagePNGRepresentation(image);
    [fileData appendData:imageData];
    [fileData appendData:KNewLine];
    
    //5.2 非文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     123456
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"123456" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //5.3 结尾标识
    /*
     --分隔符--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    return fileData;
}

@end

###2.AFN文件上传

```objc

1.文件上传拼接数据的第一种方式

[formData appendPartWithFileData:data name:@"file" fileName:@"xxoo.png" mimeType:@"application/octet-stream"];

2.文件上传拼接数据的第二种方式

 [formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"xx.png" mimeType:@"application/octet-stream" error:nil];

3.文件上传拼接数据的第三种方式

 [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];

4.【注】在资料中已经提供了一个用于文件上传的分类。

 

/*文件上传相关的代码如下*/

-(void)upload1

{

    //1.创建会话管理者

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

 

    //2.处理参数(非文件参数)

    NSDictionary *dict = @{

                           @"username":@"123"

                           };

 

    //3.发送请求上传文件

    /*

     第一个参数:请求路径(NSString类型)

     第二个参数:非文件参数,以字典的方式传递

     第三个参数:constructingBodyWithBlock 在该回调中拼接文件参数

     第四个参数:progress 进度回调

        uploadProgress.completedUnitCount:已经上传的数据大小

        uploadProgress.totalUnitCount:数据的总大小

     第五个参数:success 请求成功的回调

        task:上传Task

        responseObject:服务器返回的响应体信息(已经以JSON的方式转换为OC对象)

     第六个参数:failure 请求失败的回调

        task:上传Task

        error:错误信息

     */

    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

 

        UIImage *image = [UIImage imageNamed:@"Snip20160117_1"];

        NSData *imageData = UIImagePNGRepresentation(image);

 

        //在该block中拼接要上传的文件参数

        /*

         第一个参数:要上传的文件二进制数据

         第二个参数:文件参数对应的参数名称,此处为file是该台服务器规定的(通常会在接口文档中提供)

         第三个参数:该文件上传到服务后以什么名称保存

         第四个参数:该文件的MIMeType类型

         */

        [formData appendPartWithFileData:imageData name:@"file" fileName:@"123.png" mimeType:@"image/png"];

 

    } progress:^(NSProgress * _Nonnull uploadProgress) {

        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

 

        NSLog(@"请求成功----%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

 

        NSLog(@"请求失败----%@",error);

    }];

}

 

-(void)upload2

{

    //1.创建会话管理者

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

 

    //2.处理参数(非文件参数)

    NSDictionary *dict = @{

                           @"username":@"123"

                           };

 

    //3.发送请求上传文件

    /*

     第一个参数:请求路径(NSString类型)

     第二个参数:非文件参数,以字典的方式传递

     第三个参数:constructingBodyWithBlock 在该回调中拼接文件参数

     第四个参数:progress 进度回调

        uploadProgress.completedUnitCount:已经上传的数据大小

        uploadProgress.totalUnitCount:数据的总大小

     第五个参数:success 请求成功的回调

        task:上传Task

        responseObject:服务器返回的响应体信息(已经以JSON的方式转换为OC对象)

     第六个参数:failure 请求失败的回调

        task:上传Task

        error:错误信息

     */

    [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

 

        NSURL *fileUrl = [NSURL fileURLWithPath:@"/Users/文顶顶/Desktop/Snip20160117_1.png"];

 

 

        //在该block中拼接要上传的文件参数

        //第一种拼接方法

        /*

         第一个参数:要上传的文件的URL路径

         第二个参数:文件参数对应的参数名称,此处为file是该台服务器规定的(通常会在接口文档中提供)

         第三个参数:该文件上传到服务后以什么名称保存

         第四个参数:该文件的MIMeType类型

         第五个参数:错误信息,传地址

         */

        //[formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"1234.png" mimeType:@"image/png" error:nil];

 

 

        //第二种拼接方法:简写方法

        /*

         第一个参数:要上传的文件的URL路径

         第二个参数:文件参数对应的参数名称,此处为file

         第三个参数:错误信息

         说明:AFN内部自动获得路径URL地址的最后一个节点作为文件的名称,内部调用C语言的API获得文件的类型

         */

        [formData appendPartWithFileURL:fileUrl name:@"file" error:nil];

 

    } progress:^(NSProgress * _Nonnull uploadProgress) {

        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

 

        NSLog(@"请求成功----%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

 

        NSLog(@"请求失败----%@",error);

    }];

}

```