前言 本篇文章来介绍一下 NSURLSession 。 之前的网络基础架构NSURLConnection,被苹果在iOS9之后宣布弃用,在2013年的WWDC上,Apple揭开了NSURLConnection继任者的面纱:NSURLSession。
NSURLSession 介绍
NSURLSession 支持 http2.0 协议。
与NSURLConnection相比,NSURLSession最直接的改善就是提供了配置每个会话的缓存,协议,cookie和证书政策(credential policies)。这使得框架的网络基础架构和部分应用程序独立工作,而不会互相干扰。每一个NSURLSession对象都是根据一个NSURLSessionConfiguration初始化的,该NSURLSessionConfiguration指定了上面提到的政策,以及一系列为了提高移动设备性能而专门添加的新选项。
NSURLSession针对下载/上传等复杂的网络操作提供了专门的解决方案,针对普通、上传和下载分别对应三种不同的网络请求任务:NSURLSessionDataTask, NSURLSessionUploadTask和NSURLSessionDownloadTask。创建的task都是挂起状态,需要调用resume方法才能执行。
NSURLSessionDataTask,可以用来处理一般的网络请求,如 GET | POST 请求等。 NSURLSessionDataTask 有一个子类为 NSURLSessionUploadTask,主要用于处理上传请求。 NSURLSessionDownloadTask,主要用于处理下载请求。
NSURLSession 使用 NSURLSessionDataTask 发送 GET 请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //请求链接 NSString * urlStr = @"https://api.douban.com/v2/book/1220562"; //创建 NSURLSession 对象 NSURLSession * session = [NSURLSession sharedSession]; /** 创建 Data Task 请求 completionHandler 完成之后的回调(成功或失败) @param data 返回的数据(响应体) @param response 响应头 @param error 错误信息 */ NSURLSessionDataTask * dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlStr] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSDictionary * dataDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSLog(@"--- %@ %@ %@", dataDict, NSStringFromClass([response class]), error); }]; //执行data task [dataTask resume];
NSURLSessionDataTask 发送 POST 请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 NSURLSession * session = [NSURLSession sharedSession]; NSString * urlStr = @"https://api.weibo.com/2/statuses/update.json"; //创建可变请求对象 NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr]]; //设置请求类型 post request.HTTPMethod = @"POST"; //设置请求体 request.HTTPBody = [@"status=123&access_token=123" dataUsingEncoding:NSUTF8StringEncoding]; //创建请求 task NSURLSessionDataTask * dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //解析返回数据 NSDictionary * dataDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSLog(@"--- %@ %@ %@", dataDict, NSStringFromClass([response class]), error); }]; //执行data task [dataTask resume];
NSURLSessionDownloadTask 下载内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //下面的例子,使用NSURLSessionDownloadTask来下载一张图片 NSURLSession * session = [NSURLSession sharedSession]; //图片链接 NSString * urlStr = @"http://upload-images.jianshu.io/upload_images/288548-8240c430a7526d6a.png"; NSURLSessionDownloadTask * downloadTask = [session downloadTaskWithURL:[NSURL URLWithString:urlStr] completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { //下载完成,下载的内容是先保存在沙盒的Tmp文件夹中,location文件保存的路径 //在tmp文件中只是短暂的保存,很快就会被清除 //要想保存下来,可以移动到别的文件夹中,下面是将文件保存到Caches文件夹中 NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil]; }]; [downloadTask resume];
使用代理方法获取数据
1 2 3 4 5 6 7 8 9 //创建获取数据任务,用来获取图片数据 NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.myapp.networking.getdata"]; NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; //图片链接 NSString * urlStr = @"http://f.hiphotos.baidu.com/image/pic/item/1f178a82b9014a903ba25d77a0773912b21bee58.jpg"; NSURLSessionDataTask * dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlStr]]; [dataTask resume];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler { //开始接收数据 self.dataM = [NSMutableData data]; //必须告诉系统是否接收服务器返回的数据 completionHandler(NSURLSessionResponseAllow); } -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { //拼接服务器返回的数据 [self.dataM appendData:data]; } -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { //获取到全部数据 dispatch_async(dispatch_get_main_queue(), ^{ self.imgView.image = [UIImage imageWithData:self.dataM]; }); }
下载任务NSURLSessionDownloadTask,代理方法 NSURLSessionDownloadDelegate
1 2 3 4 5 6 NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: @"com.myapp.networking.background"]; NSOperationQueue *operationQueue = [NSOperationQueue mainQueue]; NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:operationQueue]; NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/pic/item/1f178a82b9014a903ba25d77a0773912b21bee58.jpg"]; NSURLSessionDownloadTask *downloadTask = [backgroundSession downloadTaskWithURL:url]; [downloadTask resume];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 //代理方法 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { NSLog(@"Session %@ download task %@ wrote an additional %lld bytes (total %lld bytes) out of an expected %lld bytes.\n", session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { NSLog(@"Session %@ download task %@ resumed at offset %lld bytes out of an expected %lld bytes.\n", session, downloadTask, fileOffset, expectedTotalBytes); } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSLog(@"Session %@ download task %@ finished downloading to URL %@\n", session, downloadTask, location); // Perform the completion handler for the current session //self.completionHandlers[session.configuration.identifier](); // Open the downloaded file for reading NSError *readError = nil; NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:location error:&readError]; // ... // Move the file to a new URL NSFileManager *fileManager = [NSFileManager defaultManager]; NSURL *cacheDirectory = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] firstObject]; NSError *moveError = nil; if ([fileManager moveItemAtURL:location toURL:cacheDirectory error:&moveError]) { // ... } }
Reference https://developer.apple.com/documentation/foundation/urlsession https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html#//apple_ref/doc/uid/10000165i