NSURLSesstion
NSURLConnection在IOS2出现,在iOS9被宣布弃用,NSURLSession从13年发展到现在,终于迎来了它独步江湖的时代.NSURLSession是苹果在iOS7后为HTTP数据传输提供的一系列接口,比NSURLConnection强大,坑少,好用.今天从使用的角度介绍下.
使用NSURLSession,拢共分两步: 第一步 通过NSURLSession的实例创建task 第二部 执行task 既然两步里面都出现了task,就先说说它吧. NSURLSessionTask可以简单理解为任务:如数据请求任务,下载任务,上传任务and so on.我们使用的是他的子类们: NSURLSessionTask(抽象类) NSURLSessionDataTask NSURLSessionUploadTask NSURLSessionDownloadTask 从这几个子类的名字就可以大概猜出他们的作用了.接下来我们就从不同类型的任务出发,来使用session.
NSURLSessionDataTask 字面上看是和数据相关的任务,但其实dataTask完全可以胜任downloadTask和uploadTask的工作.这可能也是我们使用最多的task种类. 简单GET请求 如果请求的数据比较简单,也不需要对返回的数据做一些复杂的操作.那么我们可以使用带block // 快捷方式获得session对象 NSURLSession *session = [NSURLSession sharedSession]; NSURL *url = [NSURL URLWithString:@"http://www.daka.com/login?username=daka&pwd=123"]; // 通过URL初始化task,在block内部可以直接对返回的数据进行处理 NSURLSessionTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError error) { NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }]; // 启动任务 [task resume]; Tips: 所有类型的task都要调用resume方法才会开始进行请求. 简单POST请求 POST和GET的区别就在于request,所以使用session的POST请求和GET过程是一样的,区别就在于对request的处理. NSURL *url = [NSURL URLWithString:@"http://www.daka.com/login"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"POST"; request.HTTPBody = [@"username=daka&pwd=123" dataUsingEncoding:NSUTF8StringEncoding]; NSURLSession *session = [NSURLSession sharedSession]; // 由于要先对request先行处理,我们通过request初始化task NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }]; [task resume]; NSURLSessionDataDelegate代理方法
NSURLSessionDataDelegate代理方法 NSURLSession提供了block方式处理返回数据的简便方式,但如果想要在接收数据过程中做进一步的处理,仍然可以调用相关的协议方法.NSURLSession的代理方法和NSURLConnection有些类似,都是分为接收响应、接收数据、请求完成几个阶段. // 使用代理方法需要设置代理,但是session的delegate属性是只读的,要想设置代理只能通过这种方式创建session NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]]; // 创建任务(因为要使用代理方法,就不需要block方式的初始化了) NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.daka.com/login?userName=daka&pwd=123"]]]; // 启动任务 [task resume]; //对应的代理方法如下: // 1.接收到服务器的响应 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { // 允许处理服务器的响应,才会继续接收服务器返回的数据 completionHandler(NSURLSessionResponseAllow); } // 2.接收到服务器的数据(可能调用多次) - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // 处理每次接收的数据 } // 3.请求成功或者失败(如果失败,error有值) - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { // 请求完成,成功或者失败的处理 }
简单下载 NSURLSessionDownloadTask同样提供了通过NSURL和NSURLRequest两种方式来初始化并通过block进行回调的方法.下面以NSURL初始化为例: SURLSession *session = [NSURLSession sharedSession]; NSURL *url = [NSURL URLWithString:@"http://www.daka.com/resources/image/icon.png"] ; NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { // location是沙盒中tmp文件夹下的一个临时url,文件下载后会存到这个位置,由于tmp中的文件随时可能被删除,所以我们需要自己需要把下载的文件挪到需要的地方 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; // 剪切文件 [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil]; }]; // 启动任务 [task resume]; 简单的上传 NSURLSessionUploadTask *task = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromFile:fileName completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { }]; 和 [self.session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"-------%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }]; 断点续传
其他 此外,task们自身有都拥有下面几个方法 - (void)suspend; - (void)resume; - (void)cancel; suspend可以让当前的任务暂停 resume方法不仅可以启动任务,还可以唤醒suspend状态的任务 cancel方法可以取消当前的任务,你也可以向处于suspend状态的任务发送cancel消息,任务如果被取消便不能再恢复到之前的状态.
NSURLSessionConfiguration 简单地说,就是session的配置信息.如: NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; // 超时时间 config.timeoutIntervalForRequest = 10; // 是否允许使用蜂窝网络(后台传输不适用) config.allowsCellularAccess = YES; // 还有很多可以设置的属性 有没有发现我们使用的Configuration都是默认配置:[NSURLSessionConfiguration defaultSessionConfiguration],其实它的配置有三种类型: + (NSURLSessionConfiguration *)defaultSessionConfiguration; + (NSURLSessionConfiguration *)ephemeralSessionConfiguration; + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier 表示了NSURLSession几种不同的工作模式. 默认的配置会将缓存存储在磁盘上,第二种瞬时会话模式不会创建持久性存储的缓存,第三种后台会话模式允许程序在后台进行上传下载工作. 除了支持任务的暂停和断点续传,我觉得NSURLSession之于NSURLConnection的最伟大的进步就是支持后台上传下载任务,这又是一个可以深入讨论的话题.但在这方面我还没有进行深入的研究,待后续了解之后另行开贴.
ASI
同步请求:
发起一个同步请求 同步意为着线程阻塞,在主线程中使用此方法会使应用Hang住而不响应任何用户事件。所以,在应用程序设计时,大多被用在专门的子线程增加用户体验,或用异步请求代替(下面会讲到)。 - (IBAction)grabURL:(id)sender { NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request startSynchronous]; NSError *error = [request error]; if (!error) { NSString *response = [request responseString]; } }
异步请求:
创建一个异步请求 异步请求的好处是不阻塞当前线程,但相对于同步请求略为复杂,至少要添加两个回调方法来获取异步事件。 下面异步请求代码完成上面同样的一件事情: - (IBAction)grabURLInBackground:(id)sender { NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDelegate:self]; [request startAsynchronous]; } - (void)requestFinished:(ASIHTTPRequest *)request { // Use when fetching text data NSString *responseString = [request responseString]; // Use when fetching binary data NSData *responseData = [request responseData]; } - (void)requestFailed:(ASIHTTPRequest *)request { NSError *error = [request error]; }
队列请求:
队列请求 提供了一个对异步请求更加精准丰富的控制。 如,可以设置在队列中,同步请求的连接数。往队列里添加的请求实例数大于maxConcurrentOperationCount时,请求实例将被置为等待,直到前面至少有一个请求完成并出列才被放到队列里执行。 也适用于当我们有多个请求需求按顺序执行的时候(可能是业务上的需要,也可能是软件上的调优),仅仅需要把maxConcurrentOperationCount设为“1”。 - (IBAction)grabURLInTheBackground:(id)sender { if (![self queue]) { [self setQueue:[[[NSOperationQueue alloc] init] autorelease]]; } NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDelegate:self]; [request setDidFinishSelector:@selector(requestDone:)]; [request setDidFailSelector:@selector(requestWentWrong:)]; [[self queue] addOperation:request]; //queue is an NSOperationQueue } - (void)requestDone:(ASIHTTPRequest *)request { NSString *response = [request responseString]; } - (void)requestWentWrong:(ASIHTTPRequest *)request { NSError *error = [request error]; } 创建NSOperationQueue,这个Cocoa架构的执行任务(NSOperation)的任务队列。我们通过ASIHTTPRequest.h的源码可以看到,此类本身就是一个NSOperation的子类。也就是说它可以直接被放到"任务队列"中,并被执行。上面的代码队了队列的创建与添加操作外,其它代码与上一例一样。
上传:
向服务器端上传数据 ASIFormDataRequest ,模拟 Form表单提交,其提交格式与 Header会自动识别。 没有文件:application/x-www-form-urlencoded 有文件:multipart/form-data ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url]; [request setPostValue:@"Ben" forKey:@"first_name"]; [request setPostValue:@"Copsey" forKey:@"last_name"]; [request setFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photo"]; [request addData:imageData withFileName:@"george.jpg" andContentType:@"image/jpeg" forKey:@"photos"];
下载:
1.创建请求队列:
首先,创建网络请求队列,如下: ASINetworkQueue *que = [[ASINetworkQueue alloc] init]; self.netWorkQueue = que; [que release]; [self.netWorkQueue reset]; [self.netWorkQueue setShowAccurateProgress:YES]; [self.netWorkQueue go];
2.设置存放路径
//初始化Documents路径 NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; //初始化临时文件路径 NSString *folderPath = [path stringByAppendingPathComponent:@"temp"]; //创建文件管理器 NSFileManager *fileManager = [NSFileManager defaultManager]; //判断temp文件夹是否存在 BOOL fileExists = [fileManager fileExistsAtPath:folderPath]; if (!fileExists) {//如果不存在说创建,因为下载时,不会自动创建文件夹 [fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];
3.发送请求
这里对下面几个对象说明一下:CustomCell是我自定义的cell,cell上面有下载和暂停两个按钮,其tag值为cell所在的行,因此这里的[sendertag]为下载按钮的tag值,self.downloadArray为array数组对象,存放要下载的资源字典信息,在该字典中有一键为URL,它对应的值就是我们下载链接。 这些东西,根据自己的实际需要改动一下即可使用 CustomCell *cell = (CustomCell *)[self.myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:[sender tag] inSection:0]]; NSString *filePath = [[self.downloadArray objectAtIndex:[sender tag]] objectForKey:@"URL"]; NSLog(@"filePath=%@",filePath); //初始下载路径 NSURL *url = [NSURL URLWithString:filePath]; //设置下载路径 ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url]; //设置ASIHTTPRequest代理 request.delegate = self; //初始化保存ZIP文件路径 NSString *savePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"book_%d.zip",[sender tag]]]; //初始化临时文件路径 NSString *tempPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"temp/book_%d.zip.temp",[sender tag]]]; //设置文件保存路径 [request setDownloadDestinationPath:savePath]; //设置临时文件路径 [request setTemporaryFileDownloadPath:tempPath]; //设置进度条的代理, [request setDownloadProgressDelegate:cell]; //设置是是否支持断点下载 [request setAllowResumeForFileDownloads:YES]; //设置基本信息 [request setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:[sender tag]],@"bookID",nil]]; NSLog(@"UserInfo=%@",request.userInfo); //添加到ASINetworkQueue队列去下载 [self.netWorkQueue addOperation:request]; //收回request [request release];
/ASIHTTPRequestDelegate,下载之前获取信息的方法,主要获取下载内容的大小,可以显示下载进度多少字节 - (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders { NSLog(@"didReceiveResponseHeaders-%@",[responseHeaders valueForKey:@"Content-Length"]); NSLog(@"contentlength=%f",request.contentLength/1024.0/1024.0); int bookid = [[request.userInfo objectForKey:@"bookID"] intValue]; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; float tempConLen = [[userDefaults objectForKey:[NSString stringWithFormat:@"book_%d_contentLength",bookid]] floatValue]; NSLog(@"tempConLen=%f",tempConLen); //如果没有保存,则持久化他的内容大小 if (tempConLen == 0 ) {//如果没有保存,则持久化他的内容大小 [userDefaults setObject:[NSNumber numberWithFloat:request.contentLength/1024.0/1024.0] forKey:[NSString stringWithFormat:@"book_%d_contentLength",bookid]]; } }
//ASIHTTPRequestDelegate,下载完成时,执行的方法 - (void)requestFinished:(ASIHTTPRequest *)request { int bookid = [[request.userInfo objectForKey:@"bookID"] intValue]; CustomCell *cell = (CustomCell *)[self.myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:bookid inSection:0]]; cell.downloadCompleteStatus = YES; cell.progressView.progress = 0.0; } 作者:风继续吹0 链接:https://www.jianshu.com/p/c24cad69f89c 來源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
AF2.0
1.实现请求的方法
2. 实现 NSURLConnection (iOS 6 & 7) AFURLConnectionOperation – 它继承于 NSOperation,负责管理 NSURLConnection,实现它的 delegate 方法。 AFHTTPRequestOperation – 它继承于 AFURLConnectionOperation,专门用于创建 HTTP 请求。2.0 的主要区别就是可以直接使用它,而不用再继承它,原因将会在下面的 Serialization 处解释。 AFHTTPRequestOperationManager – 封装 HTTP 请求的常见方式,GET / POST / PUT / DELETE / PATCH…… NSURLSession (iOS 7) AFURLSessionManager – 创建和管理 NSURLSession 对象,以及此对象的数据和下载/上传等任务,实现对象和任务的代理方法。NSURLSession 的 API 本身有一些局限,AFURLSessionManager 能使其变得更好用。 AFHTTPSessionManager – 它继承于 AFURLSessionManager,封装了 HTTP 请求的常见方式,GET / POST / PUT / DELETE / PATCH…… 总的来说:为了支持最新的 NSURLSession 接口,同时兼容旧的 NSURLConnection,2.0 的核心组件将“网络请求”和“任务处理”分离。 AFHTTPRequestOperationManager 和 AFHTTPSessionManager 提供相似的功能,切换很方便,所以从 iOS 6 移植到 iOS 7 会很容易。之前绑在 AFHTTPClient 里的 serialization、security 和 reachability 模型都被分离了出来,基于 NSURLSession 和 NSURLConnection 的 API 都可复用这些模型。
2.AFURLRequestserializtion(序列化)
概述:
RequestSerilization 是AFNetwroking中对网络请求中request这个概率的封装。它的原型其实是NSURLRequest,将NSURLRequest进行第二次封装,将许多诸如请求头,请求参数格式化, multipar/form data文件上传等进行了简化处理。 总结来说,使用AFURLRequestSerializer有以下几个优点: 1?自动处理的请求参数转义,以及对不同请求方式自动对请求参数进行格式化。 2?实现了multipart/form-data方式的请求。 3?自动处理了User-Agent,Language等请求头。
使用:
AFURLRequestSerializtion在AF框架中是封装请求这一部分对象的,作为AFHTTPSessionManaager的一个属性被使用。 如: /// request data parse manager.requestSerializer = [AFHTTPRequestSerializer serializer]; manager.requestSerializer.timeoutInterval = 30.f; 如果上传时使用的是json格式数据,那么使用AFJSONRequestSerializer: manager.requestSerializer = [AFJSONRequestSerializer serializer]; 原来存在于NSURLRequest对象的属性,都可以该对象使用如: [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"accept"];
序列化(Serialization) 2.0 架构的一个突破就是,请求和解析的可序列化。序列化的灵活性允许在网络层添加更多的商业逻辑,自定义更方便。<AFURLRequestSerializer> 和 <AFURLResponseSerializer> 这两个协议,让你在 1.0 中的一些抱怨不复存在。
3.安全
安全 AFNetworking 支持 SSL pinning。这对涉及敏感数据的 App 很重要。 AFSecurityPolicy – 这个类通过特定证书和公共密钥评估链接的安全性和可信任度。在你的 App bundle 中添加服务器证书有助于防止“中间人攻击”。
4.
可达性(Reachability) 另一个从 AFHTTPClient 中分离的功能是网络的可达性。现在你可以单独使用它,或者作为 AFHTTPRequestOperationManager / AFHTTPSessionManager 的一个属性。 AFNetworkReachabilityManager – 负责监控当前的网络可达性,当网络的可达性发生改变时,提供相应的 callback 和通知。
UIKit 扩展 2.0 的中所有 UIKit 扩展都被分离出来并进行了增强。 AFNetworkActivityIndicatorManager: 新增自动开始或结束状态栏上的网络指示器。 UIImageView+AFNetworking: 新增显示图片前剪裁或者加滤镜的功能。 UIButton+AFNetworking (新增): 类似 UIImageView+AFNetworking,按钮的背景图从线上下载。 UIActivityIndicatorView+AFNetworking (新增): 根据网络请求的状态自动开始或结束。 UIProgressView+AFNetworking (新增): 自动跟踪某个请求的上传下载的进度。 UIWebView+AFNetworking (新增): 支持网络请求的进度和内容转换。
5.集成
在 CocoaPods 中使用 AFNetworking 2.0: platform :ios, ‘7.0‘ pod "AFNetworking", "2.0.0"
6.代码
AFHTTPRequestOperation *request = [[AFHTTPRequestOperation alloc] initWithRequest:urlrequest]; request.responseSerializer = [AFJSONResponseSerializer serializer]; //设置回调的queue,默认是在mainQueue执行block回调 request.completionQueue = your_request_operation_completion_queue(); [request setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { //设置了‘completionQueue‘后,就可以在这里处理复杂的逻辑 //不用担心block住了主线程 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { }]; [request start];
时间: 2024-10-11 06:10:13