使用现状
NSURLSession是NSURLConnection的替代者,在2013年苹果全球开发者大会上(WWDC2013)随iOS7一起发布的,是对NSURLConnection进行了重构优化后的新的网络接口。从iOS9开始,NSURLConnection中发送请求的两个方法已经过期(同步请求,异步请求),初始化网络连接的方法也被设置为过期,系统不再推荐使用,建议使用NSURLSession发送网络请求
普通任务和上传
NSURLSession针对下载/上传等复杂的网络操作提供了专门的解决方案,针对普通、上传和下载分别对应三种不同的网络请求任务:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask。创建的task都是挂起状态,需要resume才能启动。
当服务器返回的数据较小时,NSURLSession与NSURLConnection执行普通任务的操作步骤没有区别。 执行上传任务时,NSURLSession与NSURLConnection一样需要设置POST请求的请求体进行上传。
下载任务方式
NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况。
而使用NSURLSessionUploadTask下载文件,会默认下载到沙盒中的tem文件中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。(后面会详细说)
请求方法的控制
NSURLConnection实例化对象,实例化开始,默认请求就发送(同步发送),不需要调用start方法。而cancel可以停止请求的发送,停止后不能继续访问,需要创建新的请求。
NSURLSession有三个控制方法,取消(cancel)、暂停(suspend)、继续(resume),暂停以后可以通过继续恢复当前的请求任务。
断点续传的方式
NSURLConnection进行断点下载,通过设置访问请求的HTTPHeaderField的Range属性,开启运行循环,NSURLConnection的代理方法作为运行循环的事件源,接收到下载数据时代理方法就会持续调用,并使用NSOutputStream管道流进行数据保存。
NSURLSession进行断点下载,当暂停下载任务后,如果downloadTask(下载任务)为非空,调用
cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler
这个方法,这个方法接收一个参数,完成处理代码块,这个代码块有一个NSData参数resumeData,如果resumeData非空,我们就保存这个对象到视图控制器的resumeData属性中,在点击再次下载时,通过调用[ [self.session downloadTaskWithResumeData:self.resumeData]resume]
方法进行继续下载操作经过以上比较可以发现,使用NSURLSession进行断点下载更加便捷.
配置信息
NSURLSession的构造方法
(sessionWithConfiguration:delegate:delegateQueue)
中有一个NSURLSessionConfiguration类的参数可以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,资源管理,网络超时等配置。NSURLConnection不能进行这个配置,相比较与NSURLConnection依赖与一个全局的配置对象,缺乏灵活性而言,NSURLSession有很大的改进了在使用自定义方式创建NSURLSession对像时,都需要传入一个NSURLSessionConfiguration参数,这个参数是对Session的网络请求的基本配置。那这个NSURLSessionConfiguration都有哪些配置呢?接着往下看
NSURLSessionConfiguration
有三个方法来创建NSURLSessionConfiguration:
- defaultSessionConfiguration 使用全局的cache,cookie,使用硬盘来缓存数据。
- ephemeralSessionConfiguration 临时session配置,与默认配置相比,这个配置不会将缓存、cookie等存在本地,只会存在内存里,所以当程序退出时,所有的数据都会消失
- backgroundSessionConfiguration 后台session配置,与默认配置类似,不同的是会在后台开启另一个线程来处理网络数据。
一旦创建了NSURLSessionConfiguration就可以给它设置各种属性
看NSURLSessionConfiguration的头文件
@interface NSURLSessionConfiguration : NSObject <NSCopying> /* 三种创建方式 */ + (NSURLSessionConfiguration *)defaultSessionConfiguration; + (NSURLSessionConfiguration *)ephemeralSessionConfiguration; + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0); /* 当使用上述第三种方式创建后台sessionConfiguration时可以读到初始化时传入的唯一标识,其他创建方式都为空 */ @property (nullable, readonly, copy) NSString *identifier; /* 缓存策略,默认值是NSURLRequestUseProtocolCachePolicy */ @property NSURLRequestCachePolicy requestCachePolicy; /* 给request指定每次接收数据超时间隔,如果下一次接受新数据用时超过该值,则发送一个请求超时给该request。默认为60s */ @property NSTimeInterval timeoutIntervalForRequest; /* 给指定resource设定一个超时时间,resource需要在时间到达之前完成。默认是7天。 */ @property NSTimeInterval timeoutIntervalForResource; /* 指定网络传输类型。精切指出传输类型,可以让系统快速响应,提高传输质量,延长电池寿命等。 typedef NS_ENUM(NSUInteger, NSURLRequestNetworkServiceType) { NSURLNetworkServiceTypeDefault = 0, // 普通网络传输,默认使用这个 NSURLNetworkServiceTypeVoIP = 1, // 网络语音通信传输,只能在VoIP使用 NSURLNetworkServiceTypeVideo = 2, // 影像传输 NSURLNetworkServiceTypeBackground = 3, // 网络后台传输,优先级不高时可使用。对用户不需要的网络操作可使用 NSURLNetworkServiceTypeVoice = 4 // 语音传输 }; */ @property NSURLRequestNetworkServiceType networkServiceType; /* 是否使用蜂窝网络,默认是yes. */ @property BOOL allowsCellularAccess; /* 是否由系统根据性能自动裁量后台任务。默认值是NO。同sessionSendsLaunchEvent一样,只对后台configuration有效。 */ @property (getter=isDiscretionary) BOOL discretionary NS_AVAILABLE(10_10, 7_0); /* 如果要为app的插件提供session,需要给这个值赋值 */ @property (nullable, copy) NSString *sharedContainerIdentifier NS_AVAILABLE(10_10, 8_0); /* 表示当后台传输结束时,是否启动app.这个属性只对 后台sessionConfiguration 生效,其他configuration类型会自动忽略该值。默认值是YES。 */ @property BOOL sessionSendsLaunchEvents NS_AVAILABLE(NA, 7_0); /* 指定了会话连接中的代理服务器。同样地,大多数面向消费者的应用程序都不需要代理,所以基本上不需要配置这个属性,默认为NULL */ @property (nullable, copy) NSDictionary *connectionProxyDictionary; /* 确定是否支持SSLProtocol版本的会话 */ @property SSLProtocol TLSMinimumSupportedProtocol; /* 确定是否支持SSLProtocol版本的会话 */ @property SSLProtocol TLSMaximumSupportedProtocol; /* 它可以被用于开启HTTP管道,这可以显着降低请求的加载时间,但是由于没有被服务器广泛支持,默认是禁用的 */ @property BOOL HTTPShouldUsePipelining; /* 默认为yes,是否提供来自shareCookieStorge的cookie,如果想要自己提供cookie,可以使用HTTPAdditionalHeaders来提供。 */ @property BOOL HTTPShouldSetCookies; /* Policy for accepting cookies. This overrides the policy otherwise specified by the cookie storage. */ @property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy; /* 指定了一组默认的可以设置出站请求的数据头。这对于跨会话共享信息,如内容类型,语言,用户代理,身份认证,是很有用的。 例如: @{@"Accept": @"application/json", @"Accept-Language": @"en", @"Authorization": authString, @"User-Agent": userAgentString } */ @property (nullable, copy) NSDictionary *HTTPAdditionalHeaders; /* 同时连接一个host的最大数。iOS默认是4.APP是作为一个整体来看的 */ @property NSInteger HTTPMaximumConnectionsPerHost; /* 存储cookie,清除存储,直接set为nil即可。 对于默认和后台的session,使用sharedHTTPCookieStorage。 对于短暂的session,cookie仅仅储存到内存,session失效时会自动清除。 */ @property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage; /* 证书存储,如果不使用,可set为nil. 默认和后台session,默认使用的sharedCredentialStorage. 短暂的session使用一个私有存储在内存中。session失效会自动清除。 */ @property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage; /* 缓存NSURLRequest的response。 默认的configuration,默认值的是sharedURLCache。 后台的configuration,默认值是nil 短暂的configuration,默认一个私有的cache于内存,session失效,cache自动清除。 */ @property (nullable, retain) NSURLCache *URLCache; /* Enable extended background idle mode for any tcp sockets created. Enabling this mode asks the system to keep the socket open * and delay reclaiming it when the process moves to the background (see https://developer.apple.com/library/ios/technotes/tn2277/_index.html) */ @property BOOL shouldUseExtendedBackgroundIdleMode NS_AVAILABLE(10_11, 9_0); /* 处理NSURLRequest的NSURLProtocol的子类。 重要:对后台Session失效。 */ @property (nullable, copy) NSArray<Class> *protocolClasses; @end
现在,我们知道如何来创建一个Session对象了,创建完Session对象,根据一个Request对象我们就可以发送网络请求了。下面看一下NSURLSession的头文件中的这些方法,如图:
从这些方法中得知,分别返回了
NSURLSessionDataTask
、NSURLSessionUploadTask
、NSURLSessionDownloadTask
,NSURLSessionStreamTask
这四个类的对象,那么这四个类是干什么呢?我们接着往下看。URLSessionTask
NSURLSessionTask是一个抽象类,其下有4个实体子类可以直接使用:
NSURLSessionDataTask
、NSURLSessionUploadTask
、NSURLSessionDownloadTask
、NSURLSessionStreamTask
。这四个子类封装了现代程序四个最基本的网络任务:获取数据,比如JSON或者XML,上传文件和下载文件还有数据流的获取。
NSURLSession比NSURLConnection最方便的地方就是任务可以暂停,继续。在网络请求中,真正去执行下载或者上传任务的就是URLSessionTask,我们来看一下它常用的方法:
- (void)resume;
当使用NSURLSession创建一个NSURLSessionTask任务时,要手动调用此方法,任务才会开启,而NSURLConnection默认开启。
- (void)suspend;
暂停任务方法,手动调用会暂停当前任务,再次开启此任务时,会从紧接上次任务开始,会面会说到如何暂停任务再开启任务。
- (void)cancel;
取消任务。NSURLSessionTask还有个属性,
@property (readonly) NSURLSessionTaskState state;
此属性标识当前任务的状态,枚举类型typedef NS_ENUM(NSInteger, NSURLSessionTaskState) { NSURLSessionTaskStateRunning = 0, /* 正在执行 */ NSURLSessionTaskStateSuspended = 1, /* 暂停状态 */ NSURLSessionTaskStateCanceling = 2, /* 取消状态*/ NSURLSessionTaskStateCompleted = 3, /* 任务完成状态 */ }
上面说到的四个类,都直接或间接继承NSURLSessionTask,所有NSURLSessionTask的方法或者属性这四个类都有,那么,简单说一下这四个类都是干什么的。
NSURLSessionDataTask
NSURLSessionDataTask是开发中使用频率最高的,我们平常使用的GET和POST请求都是通过它来实现的,如果请求的数据简单并且不需要对获取的数据进行复杂操作,我们使用 Block 解析返回的数据即可。具体代码如下:
简单 Get 请求
/** * 简单 GET 请求 */ - (void)getWithsharedSession { // 获取默认 Session NSURLSession *session = [NSURLSession sharedSession]; // 创建 URL NSURL *url = [NSURL URLWithString:@"https://www.baidu.com/s?wd=test"]; // 创建任务 task NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 获取数据后解析并输出 NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",dataStr); }]; // 启动任务 [task resume]; }
简单 POST 请求
/** * 简单 Post 请求,POST 和 GET 请求在于对 request 的处理不同,其余和 GET 相同 */ - (void)postWithSharedSession { // 获取默认 Session NSURLSession *session = [NSURLSession sharedSession]; // 创建 URL NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"]; // 创建 request NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 请求方法 request.HTTPMethod = @"POST"; // 请求体 request.HTTPBody = [@"username=1234&pwd=4321" dataUsingEncoding:NSUTF8StringEncoding]; // 创建任务 task NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 获取数据后解析并输出 NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }]; // 启动任务 [task resume]; }
另外我们也可以设置session的代理来实时的监听数据,我们可以使用NSURLSession的+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
这两个方法来设置代理,具体的协议为NSURLSessionDelegate
,它有四个直接或间接子协议NSURLSessionTaskDelegate
,NSURLSessionDownloadDelegate
和NSURLSessionStreamDelegate
、NSURLSessionDataDelegate
。具体代理方法如下://创建有代理的session - (void)sessionDataDelegate { // 创建带有代理方法的自定义 session NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; // 创建任务 NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/login?username=1234&pwd=4321"]]]; // 启动任务 [task resume]; } #pragma mark - #pragma mark - NSURLSessionDelegate // 1. 接收到服务器的响应 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { NSLog(@"接收到服务器的响应"); // 必须设置对响应进行允许处理才会执行后面两个操作。 completionHandler(NSURLSessionResponseAllow); } // 2. 接收到服务器的数据(可能调用多次) - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // 处理每次接收的数据 NSLog(@"接受到服务器的数据%s",__func__); } // 3. 请求成功或者失败(如果失败,error有值) - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { // 请求完成,成功或者失败的处理 NSLog(@"SessionTask %s",__func__); }
NSURLSessionDownloadTask
NSURLSessionDownloadTask在下载文件的时候,是将数据一点点地写入本地的临时文件。所以在 completionHandler 这个 block 里,我们需要把文件从一个临时地址移动到一个永久的地址保存起来:
/** * NSURLSessionDownloadTask 下载任务 */ - (void)downLoad { NSURLSession *session = [NSURLSession sharedSession]; NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"] ; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { // location 是沙盒中 tmp 文件夹下的一个临时 url,文件下载后会存到这个位置,由于 tmp 中的文件随时可能被删除,所以我们需要自己需要把下载的文件挪到 Caches 文件夹中 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; // 剪切文件 [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil]; NSLog(@"%@",[NSThread currentThread]); //切记当前为子线程, dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = [UIImage imageNamed:path]; }); }]; // 启动任务 [task resume]; }
代理方法下载
/** * NSURLSessionDownloadTask 代理 */ - (void)sessionDownloadTaskDelegate { // 创建带有代理方法的自定义 session NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; // 创建任务 NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"]]; // 启动任务 [task resume]; } #pragma mark - #pragma mark -NSURLSessionDownloadDelegate /** * 写入临时文件时调用 * @param bytesWritten 本次写入大小 * @param totalBytesWritten 已写入文件大小 * @param totalBytesExpectedToWrite 请求的总文件的大小 */ - (void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { //可以监听下载的进度 CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite; NSLog(@"downloadTask %f",progress); } // 2. 下载完成调用 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { // location 还是一个临时路径,需要自己挪到需要的路径(caches 文件夹) NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename]; [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil]; NSLog(@"downloadTask 移动文件路径"); }
断点续传
说一下开发中经常用到的断点续传。在开发中,我们经常由于某种原因,在下载或上传的时候往往不能一次性下载或上传完,有可能下载或上传了一半就终止了,这时候当条件满足继续下载或上传时,我们不希望从头开始,这时候就可以使用断点续传。它的大概思路是:
- 某种限制,续传暂停
- 将暂停后数据(当前数据)保存起来--_resumeData = resumeData;
- 条件允许续传时,使用resumeData创建新的NSURLSessionTask
代码:
- (IBAction)startDowning:(id)sender { if (_resumeData) { _downloadTask = [_session downloadTaskWithResumeData:_resumeData]; }else { _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; _request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://image.baidu.com/search/down?tn=download&ipn=dwnl&word=download&ie=utf8&fr=result&url=http%3A%2F%2Fb.zol-img.com.cn%2Fdesk%2Fbizhi%2Fimage%2F6%2F960x600%2F1427787678554.jpg&thumburl=http%3A%2F%2Fimg3.imgtn.bdimg.com%2Fit%2Fu%3D1996019669%2C1779575266%26fm%3D21%26gp%3D0.jpg"]]; _downloadTask = [_session downloadTaskWithRequest:_request]; } [_downloadTask resume]; } - (IBAction)stopDowning:(id)sender { if (_downloadTask) { __weak typeof (self)weakSelf = self; [_downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) { NSLog(@"%@",resumeData); weakSelf.resumeData = resumeData; weakSelf.downloadTask = nil; }]; } } #pragma mark - #pragma mark - NSURLSessionDownloadDelegate - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename]; // 剪切文件 [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil]; dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = [UIImage imageNamed:path]; }); } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite; NSLog(@"downloadTask %f",progress); dispatch_async(dispatch_get_main_queue(), ^{ self.progressView.progress = progress; }); }
注意:上面的代码是不会断点续传的,原因是这个图片的url不支持断点续传,在断点续传时,要和服务器配合好。
NSURLSessionUploadTask 在 NSURLSession 中,文件上传主要使用两种方式:
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
我们这里使用第二个方法,表单的形式上传数据- (void)upload { NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.weibo.com/2/statuses/public_timeline.json"]]; //设置HTTP请求方式 GET / POST [request setHTTPMethod:@"POST"]; //设置请求头 NSString *boundary = @"hwg"; [request setValue:[NSString stringWithFormat: @"multipart/form-data;%@", boundary]forHTTPHeaderField:@"Content-type"]; //设置请求体 //获取上传的图片的data NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"xiaoxin" ofType:@"jpeg"]]; //此处添加需要看清楚内容 NSData *body = [self httpFormDataBodyWithBoundary:boundary params:@{@"access_token":@"2.00cYYKWF6EKpiB3883361b1dJiZ4eD",@"status":@"哈哈,这是我测试NSURLSession上传文件的微博"} fieldName:@"pic" fileName:@"pic.png" fileContentType:@"image/png" data:data]; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionUploadTask *upload_task = [session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"upload success"); }]; //必须要 resume [upload_task resume]; } #pragma mark-拼接请求体 - (NSData *)httpFormDataBodyWithBoundary:(NSString *)boundary params:(NSDictionary *)params fieldName:(NSString *)fieldName fileName:(NSString *)fileName fileContentType:(NSString *)fileContentType data:(NSData *)fileData { NSString *preBoundary = [NSString stringWithFormat:@"--%@",boundary]; NSString *endBoundary = [NSString stringWithFormat:@"--%@--",boundary]; NSMutableString *body = [[NSMutableString alloc] init]; //遍历 for (NSString *key in params) { //得到当前的key //如果key不是当前的pic,说明value是字符类型,比如name:Boris //添加分界线,换行,必须使用\r\n [body appendFormat:@"%@\r\n",preBoundary]; //添加字段名称换2行 [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key]; //添加字段值 [body appendFormat:@"%@\r\n",[params objectForKey:key]]; } //添加分界线,换行 [body appendFormat:@"%@\r\n",preBoundary]; //声明pic字段,文件名为boris.png [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName]; //声明上传文件的格式 [body appendFormat:@"Content-Type: %@\r\n\r\n",fileContentType]; //声明结束符 NSString *endStr = [NSString stringWithFormat:@"\r\n%@",endBoundary]; //声明myRequestData,用来放入http body NSMutableData *myRequestData = [NSMutableData data]; //将body字符串转化为UTF8格式的二进制 [myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]]; //将image的data加入 [myRequestData appendData:fileData]; //加入结束符--hwg-- [myRequestData appendData:[endStr dataUsingEncoding:NSUTF8StringEncoding]]; return myRequestData; }
这里我们需要拼接一个表单数据,才能够上传数据。 当然,我们也可以用代理方法来监听上传的进度- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { CGFloat progress = 1.0 * totalBytesSent / bytesSent; NSLog(@"downloadTask %f",progress); }
总结:
NSURLSession 的优势
NSURLSession 支持 http2.0 协议
在处理下载任务的时候可以直接把数据下载到磁盘
支持后台下载|上传
同一个 session 发送多个请求,只需要建立一次连接(复用了TCP)
提供了全局的 session 并且可以统一配置,使用更加方便
下载的时候是多线程异步处理,效率更高
NSURLSession与NSURLConnection的前仆后继
最新推荐文章于 2019-08-10 10:17:40 发布