之前提到的NSURLConnection 是苹果提供的,当实现一个简单地网络访问的时候,效果还是不错的,但是当网络访问有了很复杂的需求的时候,NSURLConnection虽然也可以实现但是成本太高,所以,一般情况下大家都在用第三方框架,其中最受欢迎的是当年有HTTP终结者之称ASIHTTPRequest ,还有就是AFNetworking了.

  这里我们就先讲一下get方式访问吧

首先是上传,其实在iOS开发中大多数网络访问都是这么几步:

  1.获取url当然在afn里面首先需要的是一个BaseUrl这是AFHTTPClient初始化的时候必需的属性

  2.实例化一个客户端即AFHTTPClient

  3.实例化一个NSURLRequest这里如果是上传的话我们选择方式为POST

  4.用AFHTTPRequestOperation包装一个request 并设置完成时成功或者失败时回调的Block

  5.将操作抛入AFHTTPClient对象的操作队列中

下面开始文件上传代码

首先需要在类扩展里面加入两个成员变量

 AFHTTPClient    *_client;

 

然后就是实现代码了我在当前的rootview上添加了一个webview用来显示返回的html数据



1 -(void)baiduSearch:(NSString *)str
 2 {
 3     //当路径中出现中文时最好转成带百分号的unicode
 4     //    NSString *p=[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 5     //参数说明1.访问方式,这里是get,2拼接路径这里指在baseurl后面拼接的路径,会自动加'/'3参数字典将参数和参数名写入比如我传入的str是@"wisper"那么拼接完成之后是http://m.baidu.com/s?wd=wisper
 6     NSMutableURLRequest *request=[_client requestWithMethod:@"GET" path:@"s" parameters:@{@"word": str}];
 7     //使用request创建一个operation
 8     AFHTTPRequestOperation *op=[[AFHTTPRequestOperation alloc]initWithRequest:request];
 9     //设置操作完成后回调的block block传入的第一个参数是operation自己,第二个参数我们手动修改成了nsdata当然也可以不修改用之前的id
10     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, NSData* response) {
11     //既然已经知道返回的是一个html所以用字符串接收一下然后显示到webview中去
12         NSString *str=[[NSString alloc]initWithData:response encoding:NSUTF8StringEncoding];
13     //既然是多线程访问那么我们有必要将更新界面的代码扔到主线程
14     dispatch_async(dispatch_get_main_queue(), ^{
15        
16         [_webView loadHTMLString:str baseURL:_client.baseURL];
17    
18     
19     });
20         
21     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
22     //这里是网络出错的时候会调用可以打印一下err的内容这里使用断言是为了测试的时候能够更好地发现错误防止出错时被忽略
23         NSAssert(error!=nil,error.localizedDescription);
24     }];
25     //当然我们必须要把操作加入到操作队列中去
26     [_client.operationQueue addOperation:op];
27     
28 }



 接下来我们来分析一下文件下载

步骤基本和相仿只是有稍许不同,先上代码好了我直接封装成了一个方法



1 -(void)downloadfile:(NSString *)str baseURL:(NSString*)baseurl
 2 {
 3     _client=[[AFHTTPClient alloc]initWithBaseURL:[NSURL URLWithString:baseurl]];
 4     //首先需要确定文件保存的路径在这里确定是因为传入的路径需要被转换
 5     NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
 6     path=[path stringByAppendingPathComponent:[str lastPathComponent]];
 7     //    这里需要提一下的是当文件名是中文的时候需要转换成unicode否则有可能会出现错误
 8     NSString *appendPath=[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 9     
10     
11     NSURLRequest *request=[_client requestWithMethod:@"get" path:appendPath parameters:nil];
12     AFHTTPRequestOperation *op=[[AFHTTPRequestOperation alloc]initWithRequest:request];
13     //定义一个向文件输出的流,最后一个参数是,是否追加,用作断点续传的部分,断点续传会在后面提到
14     op.outputStream=[NSOutputStream outputStreamToFileAtPath:path append:NO];
15     //接下来是下载进度处理了三个参数,顾名思义1.本次读取内容,2.已经读取完成的长度;3.文件总长度
16     [op setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
17         dispatch_async(dispatch_get_main_queue(), ^{
18     //            这里去主线程更新ui
19             CGFloat progress=(CGFloat)totalBytesRead/totalBytesExpectedToRead;
20             NSLog(@"%.2f",progress);
21         });
22         
23     }];
24     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
25     
26         //下载成功操作这里可以处理文件,更新ui等
27     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
28         //下载失败操作
29     }];
30     [_client.operationQueue addOperation:op];
31     
32 }



 

  • 首先我用NSSearchPathForDirectoriesInDomains获取文件即将存放的目录,这个方法返回的是一个数组,利用编译器新特性获取到第一个元素,其实在iOS开发中也只有一个;
  • 然后我将下载链接的文件名剥离出来拼接到路径上作为文件名,这里在前面拼接文件名也是因为接下来路径需要处理一下以避免不必要的麻烦
  • 接下来我使用了nsstring的一个方法stringByAddingPercentEscapesUsingEncoding这个方法是用来处理中文的,大多数情况下中文是不能出现在网络请求中的所以我将其转成带百分号的unicod;
  • 然后我生成了一个request,并用request生成了一个AFHTTPRequestOperation
  • 设置op的输出流为文件,路径是之前生成的本地文件路径
  • 设置下载进度block,这个block是会被非常频繁的调用的,block的三个参数:bytesRead-本次读取内容,totalBytesRead-已经读取完成的                                           长度;totalBytesExpectedToRead-文件总长度

 最后不得不说一下post方式访问服务器了,上传有两种方式,一种是post 一种是put,先讲post吧



1 -(void)postwithBaseUrl:(NSString*)baseurl path:(NSString *)path
 2 {
 3     _client=[[AFHTTPClient alloc]initWithBaseURL:[NSURL URLWithString:baseurl]];
 4     NSURLRequest *request=[_client multipartFormRequestWithMethod:@"POST" path:path parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
 5         //这里需要将post中的参数拼接成一个nsdata我现在手里没有也就随便写个字符串了
 6         NSString *str=@"abc";
 7         NSData *data=[str dataUsingEncoding:NSUTF8StringEncoding];
 8         //其实这个就相当于表单数据了具体如何在开发中和后端人员协商解决
 9         [formData appendPartWithFormData:data name:@"formname"];
10     }];
11     AFHTTPRequestOperation *op=[[AFHTTPRequestOperation alloc]initWithRequest:request];
12     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
13 //    成功后调用
14     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
15 //        失败后调用
16     }];
17     [_client.operationQueue addOperation:op];



post比get就多了一个表单拼接而已,并没有复杂太多