iOS NSURLSession的用法详解和设计原理

本文详细介绍了NSURLSession的工作原理、配置方法及各种任务类型(如dataTask、uploadTask、downloadTask)的使用技巧,尤其关注NSURLSession在iOS应用中的高效数据传输实践。

NSURLSessionConfiguration *con=[NSURLSessionConfigurationdefaultSessionConfiguration];

    NSURLSession *session=[NSURLSessionsessionWithConfiguration:con];


defaultSessionConfiguration将cache和creditials储存于本地

ephemeralSessionConfiguration对数据更加保密安全,并不会向本地储存任何数据,将cache和creditials储存在内存中,并和Session绑定,当Session销毁时,对应的数据也会被销毁。

+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier

backgroundSession可以时APP处于后台时继续数据传输,其行为与defaultSession类似,但是所有的数据传输均由一个非本APP的进程来管理。也有一些功能上的限制。

在创建Session对象时通过NSURLSessionConfigration来配置,可设置Session的delegate

Session一但配置完成,就不能修改,除非创建一个新的Session对象。

NSURLSessionTask包括三种Task类型,分别为:NSURLSessionDataTask,NSURLSessionDownLoadTask,NSURLSessionUploadTask

所有的Task状态都是暂停的,需要用[Task resume]启动Task

NSURLSession有两种获取数据的方式:

初始化session时指定delegate,在代理方法中返回数据,需要实现NSURLSession的两个代理方法

初始化Session时未指定delegate的,通过block回调返回数据。

NSURLSession对象的销毁,有两种销毁模式:

- (void)invalidateAndCancel 取消该Session中的所有Task,销毁所有delegate、block和Session自身,调用后Session不能再复用。

- (void)finishTasksAndInvalidate 会立即返回,但不会取消已启动的task,而是当这些task完成时,调用delegate

这里有个地方需要注意,即:NSURLSession对象对其delegate都是强引用的,只有当Session对象invalidate, 才会释放delegate,否则会出现memory leak。

使用Session加速网络访问速度,使用同一个Session中的task访问数据,不用每次都实现三次握手,复用之前服务器和客户端之间的网络链接,从而加快访问速度

=========================================

在程序在前台时,NSURLSession与NSURLConnection可以互为替代工作。注意,如果用户强制将程序关闭,NSURLSession会断掉。NSURLSession增加来对seesion会话的支持,同时也就对应了缓存方式和缓存策略;

 
NSURLSession提供的功能:
1.通过URL将数据下载到内存
2.通过URL将数据下载到文件系统
3.将数据上传到指定URL
4.在后台完成上述功能

工作流程
如果我们需要利用NSURLSession进行数据传输我们需要:
1.创建一个NSURLSessionConfiguration,用于第二步创建NSSession时设置工作模式和网络设置:
工作模式分为:
一般模式(default):工作模式类似于原来的NSURLConnection,可以使用缓存的Cache,Cookie,鉴权。
及时模式(ephemeral):不使用缓存的Cache,Cookie,鉴权。
后台模式(background):在后台完成上传下载,创建Configuration对象的时候需要给一个NSString的ID用于追踪完成工作的Session是哪一个(后面会讲到)。
 
网络设置:参考NSURLSession中的设置项。
1. 创建一个NSURLSession,系统提供了两个创建方法:
sessionWithConfiguration:
sessionWithConfiguration:delegate:delegateQueue:
    
第一个粒度较低就是根据刚才创建的Configuration创建一个Session,系统默认创建一个新的OperationQueue处理Session的消息。
 
第二个粒度比较高,可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便。
 
2.创建一个NSURLRequest调用刚才的NSURLSession对象提供的Task函数,创建一个NSURLSessionTask。
 
根据职能不同Task有三种子类:
NSURLSessionUploadTask:上传用的Task,传完以后不会再下载返回结果;
NSURLSessionDownloadTask:下载用的Task;
NSURLSessionDataTask:可以上传内容,上传完成后再进行下载。
 
得到的Task,调用resume开始工作。
 
3.如果是细粒度的Session调用,Session与Delegate会在指定的OperationQueue中进行交互,以咱们下载例子,交互过程的顺序图如下(假如不需要鉴权,即非HTTPS请求):
4.当不再需要连接调用Session的invalidateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBecomeInvalidWithError:这个事件。Delegate收到这个事件之后会被解引用。
 
5.如果是一个BackgroundSession,在Task执行的时候,用户切到后台,Session会和ApplicationDelegate做交互。当程序切到后台后,在BackgroundSession中的Task还会继续下载,这部分文档叙述比较少,现在分三个场景分析下Session和Application的关系:
 
1)当加入了多个Task,程序没有切换到后台。
这种情况Task会按照NSURLSessionConfiguration的设置正常下载,不会和ApplicationDelegate有交互。
 
2)当加入了多个Task,程序切到后台,所有Task都完成下载。
 
在切到后台之后,Session的Delegate不会再收到,Task相关的消息,直到所有Task全都完成后,系统会调用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回调,之后“汇报”下载工作,对于每一个后台下载的Task调用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的话)和URLSession:task:didCompleteWithError:(成功或者失败都会调用)。
 
之后调用Session的Delegate回调URLSessionDidFinishEventsForBackgroundURLSession:。
 
注意:在ApplicationDelegate被唤醒后,会有个参数ComplietionHandler,这个参数是个Block,这个参数要在后面Session的Delegate中didFinish的时候调用一下,如下:
  1. @implementation APLAppDelegate 
  2.  
  3.   
  4.  
  5. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier 
  6.  
  7.   completionHandler:(void (^)())completionHandler 
  8.  
  9.  
  10.     BLog(); 
  11.  
  12.     /* 
  13.  
  14.      Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed). 
  15.  
  16.      */ 
  17.  
  18.       self.backgroundSessionCompletionHandler = completionHandler; 
  19.  
  20.  
  21. @end 
  22.  
  23.   
  24.  
  25. //Session的Delegate 
  26.  
  27. @implementation APLViewController 
  28.  
  29.   
  30.  
  31. - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session 
  32.  
  33.  
  34.     APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate]; 
  35.  
  36.     if (appDelegate.backgroundSessionCompletionHandler) { 
  37.  
  38.         void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler; 
  39.  
  40.         appDelegate.backgroundSessionCompletionHandler = nil; 
  41.  
  42.         completionHandler(); 
  43.  
  44.     } 
  45.  
  46.   
  47.  
  48.     NSLog(@"All tasks are finished"); 
  49.  
  50.  
  51. @end 
 
3)当加入了多个Task,程序切到后台,下载完成了几个Task,然后用户又切换到前台。(程序没有退出)
  
切到后台之后,Session的Delegate仍然收不到消息。在下载完成几个Task之后再切换到前台,系统会先汇报已经下载完成的Task的情况,然后继续下载没有下载完成的Task,后面的过程同第一种情况。
 
4)当加入了多个Task,程序切到后台,几个Task已经完成,但还有Task还没有下载完的时候关掉强制退出程序,然后再进入程序的时候。(程序退出了)
 
最后这个情况比较有意思,由于程序已经退出了,后面没有下完Session就不在了后面的Task肯定是失败了。但是已经下载成功的那些Task,新启动的程序也没有听“汇报”的机会了。经过实验发现,这个时候之前在NSURLSessionConfiguration设置的NSString类型的ID起作用了,当ID相同的时候,一旦生成Session对象并设置Delegate,马上可以收到上一次关闭程序之前没有汇报工作的Task的结束情况(成功或者失败)。但是当ID不相同,这些情况就收不到了,因此为了不让自己的消息被别的应用程序收到,或者收到别的应用程序的消息,起见ID还是和程序的Bundle名称绑定上比较好,至少保证唯一性。
 






=========================================================================================

NSURLSession是iOS7.0 以后用来代替NSURLConnection的网络请求框架

NSURLSession有三中任务:dataTask, uploadTask, downLoadTask;

一,

//下载文件downloadTask

- (void)downloadFile{

    //1创建session

    NSURLSession *session = [NSURLSessionsharedSession];

    //2.创建downloadtask

    NSURL *url = [NSURLURLWithString:@"http://127.0.0.1/1.mp4"];

    

    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *_Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        /*

         

        注意:保存的临时文件,block回调执行完成之后,就自动删除

         1.location从网络获取文件保存到本地的临时目录

         2.response 响应头

         3.错误

         */

        NSLog(@"%@",location.path);

        //拷贝文件到temp

        NSFileManager *fileMan = [NSFileManagerdefaultManager];

        /*

         1.A地考到b

         */

        NSString *fileSavePath = [NSTemporaryDirectory()stringByAppendingPathComponent:@"123"];

        NSLog(@"%@",fileSavePath);

        

        [fileMan copyItemAtPath:location.pathtoPath:fileSavePatherror:NULL];

        

    }];

    //3.开启任务

    [downloadTask resume];


}

_________________________________________________________________________



//带进度的下载

- (void)downloadFileWithProgress{

    //1.session

    

    /*

     需要制定delegate sessionWithConfiguration

     1.session的配置

     2.代理对象

     3.代理队列,代理方法将会在队列中执行

     */

    

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];

    NSURLSession *session = [NSURLSessionsession WithConfiguration:config delegate:selfdelegateQueue:[NSOperationQueue mainQueue]];

    

    //2.创建downloadtask

    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/1.mp4"];

    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url];

    //3.开启

    [downloadTask resume];

}


#pragma mark delegate

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask

didFinishDownloadingToURL:(NSURL *)location{

    //已经完成下载

    //location 下载文件本地路径

   //注意:::!!!!!在此代理昂发执行完成之前,需要拷贝文件

    NSLog(@" finish :   %@",location.path);

}


- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask

      didWriteData:(int64_t)bytesWritten

 totalBytesWritten:(int64_t)totalBytesWritten

totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

/*

 1.bytesWritten 本次服务器发送的数据长度

 2.totalBytesWritten 已经下载了多少

 3.totalBytesExpectedToWrite 文件的总大小

 */

//进度

    float progress = totalBytesWritten *1.0 / totalBytesExpectedToWrite;

    NSLog(@"%f",progress);

    

}


- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask

 didResumeAtOffset:(int64_t)fileOffset

expectedTotalBytes:(int64_t)expectedTotalBytes{

//续传的时候调用

}


_________________________________________________________________________




断点续传:开始,暂停,继续

/*

问题:

 1.开始.暂停,暂停,继续,崩溃

 原因:resumeData nil

 2.继续 ,崩溃

 原因:resumeData nil

 3.开始,暂停,多次继续进度混乱

 原因:开启多次下载,下载有先有后,进度不一样,显示跳动

 4.没有保存到沙盒,一断电数据没有

 

 xcode6 NSURLSessionResumeInfoTempFileName 保存文件的完整路径 

 

 /Users/apple/Library/Developer/CoreSimulator/Devices/F67DB61C-9470-4154-BA5D-1C8F4B77E44C/data/Containers/Data/Application/60F9E930-C9DF-4E15-BF47-9DE4916BB68A/tmp/123

 每次你新运行 60F9E930-C9DF-4E15-BF47-9DE4916BB68A可能会变

 

 xocde7 文件名

 */

#import "ViewController.h"


@interfaceViewController ()<NSURLSessionDownloadDelegate>


@property(nonatomic,strong)NSURLSession *session;

//下载任务

@property(nonatomic,strong)NSURLSessionDownloadTask *downloadTask;

//继续下载文件的信息

@property(nonatomic,strong)NSData *resumeData;

@property (weak,nonatomic) IBOutletUIProgressView *progressView;


@end


@implementation ViewController


//懒加载

-(NSURLSession *)session{

    if(!_session){

        NSURLSessionConfiguration *config = [NSURLSessionConfigurationdefaultSessionConfiguration];

        _session = [NSURLSessionsessionWithConfiguration:configdelegate:selfdelegateQueue:nil];

    }

    return_session;

}



//开启下载

- (IBAction)beginClick:(id)sender {

    [selfdownloadFileWithProgress];

}


//暂停下载

- (IBAction)pauseClick:(id)sender {

    

   //返回当前下载文件的信息

    [self.downloadTask cancelByProducingResumeData:^(NSData *_Nullable resumeData) {

        self.resumeData = resumeData;

        NSLog(@"%@",resumeData);

        //保存resumeData到沙盒

        NSString *tmp =[NSTemporaryDirectory() stringByAppendingPathComponent:@"123"];

        [resumeData writeToFile:tmpatomically:YES];

        NSLog(@"%@",tmp);

    }];

    

    self.downloadTask =nil;

}


//点击继续

- (IBAction)resumeClick:(id)sender {

    

   //从沙盒读取之前下载的信息

    NSString *tmp =[NSTemporaryDirectory() stringByAppendingPathComponent:@"123"];

   //判断文件是否存在

    NSFileManager *fileMan = [NSFileManagerdefaultManager];

    if([fileMan fileExistsAtPath:tmp]){

        NSData *data =[NSDatadataWithContentsOfFile:tmp];

        self.resumeData = data;

    }

    

    //判断resumeData

    if(!self.resumeData){

        return;

    }

    

   //继续下载,上次下载文件的信息

    self.downloadTask  = [self.session downloadTaskWithResumeData:self.resumeData];

    //开启下载

    [self.downloadTaskresume];

    

    self.resumeData =nil;

    

}

//带进度的下载

- (void)downloadFileWithProgress{

    

    //1.创建downloadtask

    NSURL *url = [NSURLURLWithString:@"http://127.0.0.1/1.mp4"];

    self.downloadTask = [self.sessiondownloadTaskWithURL:url];

    //2.开启

    [self.downloadTaskresume];

    

}


#pragma mark delegate

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask

didFinishDownloadingToURL:(NSURL *)location{

    //已经完成下载

    //location 下载文件本地路径

   //注意:::!!!!!在此代理昂发执行完成之前,需要拷贝文件

    NSLog(@" finish :   %@",location.path);

}


- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask

      didWriteData:(int64_t)bytesWritten

 totalBytesWritten:(int64_t)totalBytesWritten

totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

/*

 1.bytesWritten 本次服务器发送的数据长度

 2.totalBytesWritten 已经下载了多少

 3.totalBytesExpectedToWrite 文件的总大小

 */

//进度

    

    NSLog(@"%@",[NSThreadcurrentThread]);

    float progress = totalBytesWritten *1.0 / totalBytesExpectedToWrite;

    NSLog(@"%f",progress);

    self.progressView.progress = progress;

}


- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask

 didResumeAtOffset:(int64_t)fileOffset

expectedTotalBytes:(int64_t)expectedTotalBytes{

//续传的时候调用

}




_________________________________________________________________________





二,
上传

- (void)uploadFile{

//1.session

    NSURLSession *session =[NSURLSessionsharedSession];

    

    NSURL *url = [NSURLURLWithString:@"http://127.0.0.1/uploads/2.JPG"];//服务器的路径

    

    //3请求

    NSMutableURLRequest *request = [NSMutableURLRequestrequestWithURL:url];

    //put方式提交数据

    request.HTTPMethod =@"put";

    

    //Authorization: Basic YWRtaW46YWRtaW4=  -----   admin:admin

    [request setValue:[selfgetAuthWithUsername:@"admin"password:@"admin"]forHTTPHeaderField:@"Authorization"];

    

    //文件的URL

    NSURL *fileURL = [[NSBundlemainBundle]URLForResource:@"2.JPG"withExtension:nil];//需要上传的文件本地路径

    

    //2.创建上传任务

   NSURLSessionUploadTask *uploadTask = [sessionuploadTaskWithRequest:requestfromFile:fileURLcompletionHandler:^(NSData *_Nullable data,NSURLResponse *_Nullable response,NSError *_Nullable error) {

       

       /*

        1.响应体

        2.响应头

        3.错误

        */

       

       NSLog(@"%@",data);

       NSLog(@"%@",response);

       

    }];

    

    //4 开启

    [uploadTask resume];

}


//拼接Authorization

//Authorization: Basic YWRtaW46YWRtaW4=  -----   admin:admin

-(NSString *)getAuthWithUsername:(NSString *)username password:(NSString *)password{

    //1.拼接用户名和密码 admin:admin

    NSString *str = [NSStringstringWithFormat:@"%@:%@",username,password];

    //YWRtaW46YWRtaW4=

    NSString *base64String = [selfbase64Encode:str];

    

    return [NSStringstringWithFormat:@"Basic %@",base64String];

}



//base64编码

-(NSString *)base64Encode:(NSString *)str{

    NSData *data = [strdataUsingEncoding:NSUTF8StringEncoding];

    return [database64EncodedStringWithOptions:0];

}




_________________________________________________________________________

上传带进度

#import "ViewController.h"


@interfaceViewController ()<NSURLSessionTaskDelegate>


@property(nonatomic,strong)NSURLSession *session;


@end


@implementation ViewController

//懒加载

-(NSURLSession *)session{

    if(!_session){

        NSURLSessionConfiguration *config = [NSURLSessionConfigurationdefaultSessionConfiguration];

        

        _session = [NSURLSessionsessionWithConfiguration:configdelegate:selfdelegateQueue:[NSOperationQueuemainQueue]];

    }

    return_session;

}


- (void)viewDidLoad {

    [superviewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    [selfuploadFileWithProgress];

}



-(void)uploadFileWithProgress{


    NSURL *url = [NSURLURLWithString:@"http://127.0.0.1/uploads/2.JPG"];

    

    //3请求

    NSMutableURLRequest *request = [NSMutableURLRequestrequestWithURL:url];

    //put方式提交数据

    request.HTTPMethod =@"put";

    

    //Authorization: Basic YWRtaW46YWRtaW4=  -----   admin:admin

    [request setValue:[self getAuthWithUsername:@"admin"password:@"admin"]forHTTPHeaderField:@"Authorization"];

    

    //文件的URL

    NSURL *fileURL = [[NSBundlemainBundle]URLForResource:@"2.JPG"withExtension:nil];

    

    //2.上传任务

    NSURLSessionUploadTask *uploadTask = [self.sessionuploadTaskWithRequest:requestfromFile:fileURL];

    //3.开启任务

    [uploadTask resume];

}


//代理方法

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task

   didSendBodyData:(int64_t)bytesSent

    totalBytesSent:(int64_t)totalBytesSent

totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{

/*

 1.bytesSent 本次发送的数据长度

 2.totalBytesSent 已经发送的数据长度

 3.totalBytesExpectedToSend 要发送的文件总长度

 */

    float progress = totalBytesSent *1.0 / totalBytesExpectedToSend;

    NSLog(@"%f",progress);

    

}


//拼接Authorization

//Authorization: Basic YWRtaW46YWRtaW4=  -----   admin:admin

-(NSString *)getAuthWithUsername:(NSString *)username password:(NSString *)password{

    //1.拼接用户名和密码 admin:admin

    NSString *str = [NSString stringWithFormat:@"%@:%@",username,password];

    //YWRtaW46YWRtaW4=

    NSString *base64String = [self base64Encode:str];

    

    return [NSString stringWithFormat:@"Basic %@",base64String];

}



//base64编码

-(NSString *)base64Encode:(NSString *)str{

    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];

    return [data base64EncodedStringWithOptions:0];

}

@end



_____________________________________________________________________________________

dataTask:get方法(1,get方法一般用来获取浏览器上的数据,通过URL传递数据,不安全但是效率高,get请求的结果能被浏                          览器缓存)URL中有中文或空格要进行URL编码,浏览器自动做编码转换.URL编码就是把汉字和空格还在那                        换成% +16进制数的形式.

                   2,URL中的参数,  ? 后面跟要传到服务器的参数(http协议的一部分),参数以键值对的形式传递,多个参数之间                        使用&连接.

    NSURL *url = [NSURLURLWithString:@"http://127.0.0.1/login.php?username=1111&password=111"];

    

    [[[NSURLSessionsharedSession] dataTaskWithURL:urlcompletionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError * _Nullable error) {

        

        

        NSString *string = [[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding];

        NSLog(@"%@",string);

        

    }] resume];


_____________________________________________________________________________________

dataTask:POST方法(post是通过请求体传输数据,安全但是效率低,post请求不能被浏览器缓存)

    NSURL *url = [NSURLURLWithString:@"http://127.0.0.1/login.php"];

    

    //创建request

    NSMutableURLRequest *request = [NSMutableURLRequestrequestWithURL:url];

    //post

    request.HTTPMethod =@"post";//[request setHTTPMethod:@"post"]; //指定请求方式

    //请求体

    NSString *bodyString =@"username=1111&password=111";

    request.HTTPBody = [body StringdataUsingEncoding:NSUTF8StringEncoding];//[request setHTTPBody:bodyData];  //设置请求的参数

    [request setURL:[NSURLURLWithString:url]]; //设置请求的地址

    


    [[[NSURLSessionsharedSession] dataTaskWithRequest:requestcompletionHandler:^(NSData *_Nullable data,NSURLResponse *_Nullable response,NSError *_Nullable error) {

        

        NSString *string = [[NSStringalloc]initWithData:data encoding:NSUTF8StringEncoding];

        NSLog(@"%@",string);

        

    }] resume];


======================
POST方法上传:
- (void)upDataFile
{
    /**
     *  文件上传的时候需要设置请求头中Content-Type类型, 必须使用URL编码,
      
     application/x-www-form-urlencoded:默认值,发送前对所有发送数据进行url编码,支持浏览器访问,通常文本内容提交常用这种方式。
     multipart/form-data:多部分表单数据,支持浏览器访问,不进行任何编码,通常用于文件传输(此时传递的是二进制数据) 。
     text/plain:普通文本数据类型,支持浏览器访问,发送前其中的空格替换为“+”,但是不对特殊字符编码。
     application/json:json数据类型,浏览器访问不支持 。
     text/xml:xml数据类型,浏览器访问不支持。
      
     multipart/form-data 必须进行设置,
     */
    // 1. 创建URL
    NSString *urlStr = @"url";
    urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 2. 创建请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置请求的为POST
    request.HTTPMethod = @"POST";
     
    // 3.构建要上传的数据
    NSString *path = [[NSBundle mainBundle] pathForResource:@"123"ofType:@"123"];
    NSData *data = [NSData dataWithContentsOfFile:path];
     
    // 设置request的body
    request.HTTPBody = data;
     
    // 设置请求 Content-Length
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
    // 设置请求 Content-Type
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"Xia"] forHTTPHeaderField:@"Content-Type"];
     
    // 4. 创建会话
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if(!error) {
            // 上传成功
        }else{
            // 上传失败, 打印error信息
            NSLog(@"error --- %@", error.localizedDescription);
        }
    }];
    // 恢复线程 启动任务
    [uploadTask resume];
     
}

_____________________________________________________________________________________
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值