OC的NSURLSession
上一次的WWCD大会发布,说明了要废弃NSURLConnection,估计很多人蛋疼了。在Xcode7中已经不能使用NSURLConnection了,这样也导致了很多第三方框架不能在Xcode7中使用。NSURLSession的崛起已成为了必然!
为了适应IT这个行业必须不断更新知识,不断充实自己,所以我认真的学习了一下NSURLSession。
NSURLSession的简介(IOS 7.0以后出现):NSURLSession是一组相互依赖的类,它的大部分组件和NSURLConnection中的组件相同如NSURLRequest,NSURLCache等。而NSURLSession的不同之处在于,它将NSURLConnection替换为NSURLSession和NSURLSessionConfiguration,以及3个NSURLSessionTask的子类:NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask。
1.支持后台运行网络任务
2.暂停、停止、重启网络任务,不再需要 NSOperation
封装
3.请求可以使用同样的配置容器
4.不同的 session
可以使用不同的私有存储
5.block
和代理
可以同时起作用
6.直接从文件系统上传、下载
注意:为了方便程序员使用,苹果提供了一个全局 session
所有的 任务(Task)
都是由 Session
发起的
所有的任务默认是挂起
的,需要 Resume,很多时候很多人在使用的时候都会忘记写resume。
session
的回调是异步的
NSURLSession的成员变量NSURLSessionConfiguration:
NSURLSessionConfiguration
用于设置全局的网络会话属性,包括:身份验证,超时时长,缓存策略,Cookie 等,可以代替NSURLRequest。
NSURLSessionConfiguration
有三个类构造方法是为不同的用例设计的
1.
+ (NSURLSessionConfiguration *)defaultSessionConfiguration- 返回标准配置,具有共享 NSHTTPCookieStorage(cookie仓库)
,NSURLCache(路径缓存)
和 NSURLCredentialStorage(证书仓库)。
2.
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration- 返回一个预设配置,没有持久性存储的缓存,Cookie或证书。这对于实现像秘密浏览
功能的功能来说,是很理想的
3.
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0)-独特之处在于,会创建一个后台会话。后台会话不同于常规的,普通的会话,它甚至可以在应用程序挂起,退出,崩溃的情况下运行上传和下载任务。初始化时指定的标识符,被用于向任何可能在进程外恢复后台传输的守护进程提供上下文
NSURLSessionConfiguration的常用属性
//Hosts是一个系统文件,记录了一些网站的IP地址和域名的对应关系
//Cookie就是服务器暂存放在你计算机上的一笔资料,好让服务器用来辨认你的计算机\
NSURLSessionConfiguration-->HTTPShouldSetCookies是否应该设置cookie HTTPCookieAcceptPolicy设置cookie的选择
属性 | 描述 |
---|---|
HTTPAdditionalHeaders | HTTP 头字段 |
timeoutIntervalForRequest | 超时时长 |
timeoutIntervalForResource | 整个资源请求时长 |
requestCachePolicy | 缓存策略 |
allowsCellularAccess | 允许蜂窝访问 |
HTTPMaximumConnectionsPerHost | 对于一个host的最大并发连接数,默认数值是 4,MAC 下的默认数值是 6 |
NSURLSession注意事项
一旦指定了 session 的代理,session会对代理进行强引用,如果不主动取消 session,会造成内存泄漏!
解决方案
解决方法1:在任务完成后取消 session
缺点:session一旦被取消就无法再次使用
解决方法2:在视图将要消失的时候取消 session
优点:只需要一个全局的session统一管理
NSURLSession支持的三种任务:
NSURLSession类支持三种类型的任务:加载数据(NSURLSessionDataTask),下载(NSURLSessionDownloadTask)和上传(NSURLSessionUploadTask)。
加载数据代码演示:
- (void)sessionDemo1 { // 1. url NSURL *url = [NSURL URLWithString:@"http://localhost/demo.json"]; // 2. session NSURLSession *session = [NSURLSession sharedSession]; // 3. 数据任务 NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; NSLog(@"%@ %@ %@", result, response, [NSThread currentThread]); }]; // 4. 继续任务 [task resume]; }
下载文件数据代码简单演示:
注意:块代码回调结束后,下载的文件会被删除
- (void)download { NSLog(@"开始"); // 1. url NSURL *url = [NSURL URLWithString:@"http://localhost/321.zip"]; // 2. 下载 [[[NSURLSession sharedSession] downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { NSLog(@"%@ %@", location, [NSThread currentThread]); }] resume]; }
上传文件数据代码演示:
上传文件
#define boundary @"itcast-upload" - (void)uploadFile:(NSString *)fieldName dataDict:(NSDictionary *)dataDict params:(NSDictionary *)params { // 1. url - 负责上传文件的脚本 NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload-m.php"]; // 2. request NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"POST"; NSString *typeValue = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request setValue:typeValue forHTTPHeaderField:@"Content-Type"]; NSData *data = [self formData:fieldName dataDict:dataDict params:params]; // 3. 上传 [[[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@ %@", response, [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]); }] resume]; }
拼接数据体
/// 生成 formData 二进制数据 /// /// @param fieldName 服务器字段名 /// @param dataDict 上传文件数据字典 "保存在服务器文件名": 二进制数据 /// @param params 提交参数字典 /// /// @return formData 二进制数据 - (NSData *)formData:(NSString *)fieldName dataDict:(NSDictionary *)dataDict params:(NSDictionary *)params { NSMutableData *dataM = [NSMutableData data]; // 1. 生成文件数据 [dataDict enumerateKeysAndObjectsUsingBlock:^(NSString *fileName, NSData *fileData, BOOL *stop) { NSMutableString *strM = [NSMutableString string]; [strM appendFormat:@"--%@\r\n", boundary]; [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, fileName]; [strM appendString:@"Content-Type: application/octet-stream\r\n\r\n"]; [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]]; [dataM appendData:fileData]; [dataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; }]; // 2. 生成参数数据 [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { NSMutableString *strM = [NSMutableString string]; [strM appendFormat:@"--%@\r\n", boundary]; [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]; [strM appendString:value]; [strM appendString:@"\r\n"]; [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]]; }]; // 3. 结尾字符串 NSString *tail = [NSString stringWithFormat:@"--%@--", boundary]; [dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]]; return dataM.copy; }
开始上传
- (void)uploadFileDemo { // 1. 上传文件数据 NSURL *fileURL1 = [[NSBundle mainBundle] URLForResource:@"001.png" withExtension:nil]; NSData *data1 = [NSData dataWithContentsOfURL:fileURL1]; NSURL *fileURL2 = [[NSBundle mainBundle] URLForResource:@"demo.jpg" withExtension:nil]; NSData *data2 = [NSData dataWithContentsOfURL:fileURL2]; // 如何传递参数 - 用字典传递参数 NSDictionary *dataDict = @{@"001.png": data1, @"002.jpg": data2}; // 2. 字符串参数 NSDictionary *params = @{@"status": @"how are you"}; // 3. 上传文件并且提交参数 [self uploadFile:@"userfile[]" dataDict:dataDict params:params]; }