iOS网络高级编程—网络功能(构建请求)

在了解完iOS网络层次之后,开始从高层(Cocoa)一步步学习。以最常使用的HTTP请求为基础。

iOS高层网络API主要有3个方法可以执行请求和响应。分别是:同步、队列式异步、异步。

1、同步请求

同步请求是最简单最基础的请求类型。在主线程中使用时可能会发生阻塞现象,一般都不在主线程中使用这种方法。但是如果在异步线程中使用的话,便成了异步请求。

来看下简单的同步请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-(void)requestSync{
NSURL *url = [NSURL URLWithString:TestUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSHTTPURLResponse *response;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(error!=nil){
NSLog(@"error:%@",error);
return;
}
if([response isKindOfClass:[NSHTTPURLResponse class]]){
if(response.statusCode!=200){
NSLog(@"response unreach");
return;
}
}
NSString *result = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"data:%@",result);
}

需要注意的是sendSynchronousRequest函数传入的是指针Response、error。

2、队列式异步请求

队列式请求主要调用NSOperationQueue类。应用启动时,程序的主队列就会创建,可以通过NSOperationQueue的mainQueue方法来获取,但不能在主队列进行网络请求的耗时操作,会阻塞UI。

可以通过NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 来创建新的队列,默认情况下的并发操作数量由系统决定,但可以通过调用setMaxConcurrentOperationCount:方法来重新设置。

下面是一段队列式异步请求的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-(void)requestQueue{
NSURL *url = [NSURL URLWithString:TestUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error){
if(error!=nil){
NSLog(@"error:%@",error);
return;
}
if([response isKindOfClass:[NSHTTPURLResponse class]]){
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if(httpResponse.statusCode != 200){
NSLog(@"response unreach");
return;
}
}
NSString *result = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"data:%@",result);
}];
}

相对于同步请求,队列式异步请求已经可以直接运用于项目的业务逻辑了,需要注意的是NSOperationQueue一般只创建一次,这时候可以使用单例模式来调用。NSOperationQueue是一个很重要的多线程类,可以运用于多种耗时操作中,多种业务逻辑可以创建多个Queue来使用。

3、异步请求

异步请求采用的是Delegate形式,通过实现协议函数,处理时更加灵活,但直接在业务层使用时就显得有点效率低,可以先封装函数,用block回调就提高效率了。

来看一下调用代码:

1
2
3
4
5
6
7
-(void)requestAsyc{
NSURL *url = [NSURL URLWithString:TestUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[conn start];
}

需要注意的是,异步请求需要RunLoop来处理回调,这个时候NSURLConnection不能直接启动,需要设置RunLoop后再启动。

start之后,就要在继承的协议函数中进行处理了。

  1. connection:willSendRequest:redirectResponse: 在执行请求之前调用,处理网络协议的重定向。

  2. connection:didReceiveResponse: 在发送完HTTP协议头文件,接收到服务器HTTP响应后调用,这个时候可以验证statusCode是不是200。

  3. connection:didReceiveData: 接收HTTP协议体数据时调用,发生在connection:didReceiveResponse:之后,可以统计下载的数据百分比。

  4. connection:didFailWithError: 很明显,就是在连接失败的时候调用。调用这个方法后该次请求就被终止了。

  5. connectionDidFinishLoading: 完成加载并接收到全部数据后调用。

除此之外还有几个一般情况下不需要处理的函数:

  1. connection:needNewBodyStream: 用于重新向请求体的输入流发出请求。

  2. connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: 在不确定的时间间隔内调用该委托以报告上传进度。

  3. connect:willCacheResponse: 该可选方法向委托提供了一种方式来检测与修改协议控制器所缓存的响应。

以上就是Cocoa层的三种请求方法,一般情况下并不直接使用,而是进一步封装之后才在业务层调用。