iOS网络: NSURLConnection进行异步请求
介绍:
iOS 的应用,一般是需要通过网络进行数据的交互的,这样你的应用就成为了联机的应用了。
iOS SDK 允许我们向网络发送请求,并且能够很方便的通过 NSURLConnection 这个类 来获取和发送数据,我们可以通过 NSJSONSerialization 对 JSON 进行序列化和反序列化。 XML 的解析则使用 NSXMLParser 类。可以通过 Twitter 框架进行 Twitter 进行连接。
一 通过NSURLConnection进行异步下载
1.
NSURLConnection 提供了两种方式来实现连接,一种是同步的另一种是异步的,异步 的连接将会创建一个新的线程,这个线程将会来负责下载的动作。而对于同步连接,在下载 连接和处理通讯时,则会阻塞当前调用线程。
许多开发者都会认为同步的连接将会堵塞主线程,其实这种观点是错误的。一个同步的连接是会阻塞调用它的线程。如果你在主线程中创建一个同步连接,没错,主线程会阻塞。 但是如果你并不是从主线程开启的一个同步的连接,它将会类似异步的连接一样。因此这种情况并不会堵塞你的主线程。事实上,同步和异步的主要区别就是运行 runtime 为会异步连接创建一个线程,而同步连接则不会。
2.
为了能够创建一个异步的请求连接,我们需要做如下的操作。
1. 创建一个 NSSring 类型的 URL 连接字符串。
2. 把 NSString 类型转化成 NSURL 类型。
3. 把我们的URL对象赋值到 NSURLRequest 对象中,如果是多个连接请求,请使用 NSMutableURLRequest.
1. 创建一个 NSSring 类型的 URL 连接字符串。
2. 把 NSString 类型转化成 NSURL 类型。
3. 把我们的URL对象赋值到 NSURLRequest 对象中,如果是多个连接请求,请使用 NSMutableURLRequest.
4. 创建一个 NSURLConnection 的连接实例,然后把我们定义好的 URL 请求赋值过去。
我们可以通过 NSURLConnection 的 sendAsynchronousRequest:queue:completionHandler 这个方法创建一个异步的 URL 连接对象。这个方法的参数如下:
sendAsynchronousRequest
异步请求
Queue
一个操作队列,我们可以很轻松的分配和初始化一个操作队列,然后可以根据我们需求添加
到这个参数中。
completionHandler
这是一个 block 对象,当我们异步的连接操作完成之后,无论我们的异步操作是否成功,都会执行这个 block,这个 block 对象都能够接收到如下三个参数:
1).一个 NSURLResopne,这个对象封装了服务器返回给我们 response。
2).NSData,可选的,这个是我们通过 URL 请求返回的数据。
3).NSError 类型的对象,如果请求中有错误发生。
注意:
sendAsynchronousRequest:queue:completionHandler: 方法不会在主线程中调用。因此如果你想执行一个跟 UI 相关的任务,那么请回到主线程中。
例子:
- (void)sendAsynNetWork{ NSString *urlString = @"http://www.apple.com"; NSURL *url = [NSURL URLWithString:urlString]; NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //发送异步请求 [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { if ([data length] > 0 && connectionError == nil) { NSString *html = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"HTML = %@",html); //保存从网络上下载的数据到你的硬盘中 //1.获取存储路径 NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]; //将文件名添加到存储路径上,形成文件路径 NSString *filePath = [documentsDir stringByAppendingPathComponent:@"apple.html"]; //将数据写入文件 存到硬盘 [data writeToFile:filePath atomically:YES]; NSLog(@"Successfully saved the file to %@",filePath); } else if ([data length] == 0 && connectionError == nil){ NSLog(@"Nothing was downloaded"); } else if (connectionError != nil){ NSLog(@"connectionError happened = %@",connectionError); } }]; }
在 iOS SDK 早期的版本中,URL 连接使用的是 delegation 模型,不过,现在全部都使用 block 了,你不用在考虑实现 delegate 方法。
二. 处理异步连接中的超时
创建一个异步的请求的时候,你想设置一个响应超时的值,来完善你的应用程序
讨论:
当初始化 NSURLRequest 这个对象,并且把这个对象传递给 URL 连接对象的时候,你可以使用 requestWithURL:cachePolicy:timeoutInterval:这个类方法,将超时的值传递给 timeoutInterval 参数。
这里详细看第二个参数 cachePolicy: 参数值在 NSURLRequestCachePolicy(缓存策略) 枚举中选择:
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
1> NSURLRequestUseProtocolCachePolicy = 0, 默认的缓存策略, 如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断下一步操作,如: Cache-Control字段为must-revalidata, 则询问服务端该数据是否有更新,无更新的话直接返回给用户缓存数据,若已更新,则请求服务端.
2> NSURLRequestReloadIgnoringLocalCacheData = 1, 忽略本地缓存数据,直接请求服务端.
3> NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, 忽略本地缓存,代理服务器以及其他中介,直接请求源服务端.
4> NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData
5> NSURLRequestReturnCacheDataElseLoad = 2, 有缓存就使用,不管其有效性(即忽略Cache-Control字段), 无则请求服务端.
6> NSURLRequestReturnCacheDataDontLoad = 3, 死活加载本地缓存. 没有就失败. (确定当前无网络时使用)
7> NSURLRequestReloadRevalidatingCacheData = 5, 缓存数据必须得得到服务端确认有效才使用(貌似是NSURLRequestUseProtocolCachePolicy中的一种情况)
};
Tips: URL Loading System默认只支持如下5中协议: 其中只有http://和https://才有缓存策略.
(1) http://
(2) https://
(3) ftp://
(4) file://
(5) data://
//设置更详细的request 第二个参数缓存策略 第三个参数最大等待时间 NSURLRequest *urlrequest1 = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:15.0f];