您的位置:首页 > 理论基础 > 计算机网络

iOS开发网络数据之AFNetworking使用

2015-12-14 11:15 471 查看
http网络库是集XML解析,Json解析,网络图片下载,plist解析,数据流请求操作,上传,下载,缓存等网络众多功能于一身的强大的类库。最新版本支持session,xctool单元测试。网络获取数据一直是手机软件的重中之重,如果处理的不好,会造成很差的用户体验。随着ASIHTTPRequest的停止更新,更换网络库是必然的事情,AFNetworking就是很好的替代品。而且都是轻量级,不要担心加入太多库会多软件性能有影响。
1.为什么用第三方网络库?先说如果不用网络库,我曾有一次觉得什么都用苹果原生的好,XML解析用苹果自带的委托,下载图片自己写,如果你也有跟我一样的经历,那你会发现自己管理起来很复杂,很容易出错。而且性能不好。如果你是一个追求完美的人,那就放下你的固执,就如当初的我一样,尝试一下网络库吧。
2.为什么要用AFNetworking?第一点,它有人更新和维护,而且目前使用者很多,第二点,还是使用者很多,那么他的资料,文档,demo就多,很好找遇到问题好解决。如果不用AFNetworking,还有一种MKNetworkKit也不错,不妨一试。
如何选择AFNetworking版本

首先得下载AFNetworking库文件,下载时得首先弄清楚,你将要开发的软件兼容的最低版本是多少。AFNetworking2.0或者之后的版本需要xcode5.0版本并且只能为IOS6或更高的手机系统上运行,如果开发MAC程序,那么2.0版本只能在MACOS
X 10.8或者更高的版本上运行。

AFNetworking2.0的下载地址https://github.com/AFNetworking/AFNetworking
如果你想要兼容IOS5或MAC OS X 10.7,那你需要用最新发布的1.x版本
AFNetworking1.x的下载地址https://github.com/AFNetworking/AFNetworking/tree/1.x
如果要兼容4.3或者MAC OS X 10.6,需要用最新发布的0.10.x版本
AFNetworking 0.10.xhttps://github.com/AFNetworking/AFNetworking/tree/0.10.x

2013年大多数软件兼容的最低版本为4.3,而2014年,估计大多数软件兼容的最低版本将会是5.0甚至6.0;
所以,目前最好的选择还是1.x版本,兼容到IOS5.0。
如何通过URL获取json数据
第一种,利用AFJSONRequestOperation,官方网站上给的例子:

   NSString
*str=[NSString
stringWithFormat:@"https://alpha-api.app.net/stream/0/posts/stream/global"];

   NSURL
*url =[NSURL URLWithString:[strstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

   NSURLRequest
*request = [NSURLRequestrequestWithURL:url];

   //   从URL获取json数据

   AFJSONRequestOperation
*operation1 = [AFJSONRequestOperationJSONRequestOperationWithRequest:request success:^(NSURLRequest
*request, NSHTTPURLResponse
*response, NSDictionary* JSON) {
             NSLog(@"获取到的数据为:%@",JSON);
    }
failure:^(NSURLRequest *request,
NSHTTPURLResponse *response,
NSError *error, id data) {
      NSLog(@"发生错误!%@",error);
    }];
    [operation1
start];

第二种方法,利用AFHTTPRequestOperation 先获取到字符串形式的数据,然后转换成json格式,将NSString格式的数据转换成json数据,利用IOS5自带的json解析方法:

   NSString *str=[NSString stringWithFormat:@"https://alpha-api.app.net/stream/0/posts/stream/global"];

   NSURL *url =[NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

   NSURLRequest *request =[NSURLRequest requestWithURL:url];

  AFHTTPRequestOperation*operation =[[AFHTTPRequestOperationalloc]
initWithRequest:request];

   [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation
*operation, id
responseObject) {
      NSString*html = operation.responseString;

           NSData* data=[html dataUsingEncoding:NSUTF8StringEncoding];

           id
dict=[NSJSONSerialization JSONObjectWithData:dataoptions:0 error:nil];
      NSLog(@"获取到的数据为:%@",dict);

   }failure:^(AFHTTPRequestOperation
*operation, NSError
*error) {
      NSLog(@"发生错误!%@",error);
    }];

   NSOperationQueue
*queue = [[NSOperationQueuealloc] init];
    [queue
addOperation:operation];

如果发生Error Domain=NSURLErrorDomain Code=-1000 "bad URL"UserInfo=0x14defc80 {NSUnderlyingError=0x14deea10 "bad URL",NSLocalizedDescription=bad URL这个错误,请检查URL编码格式。有没有进行stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding

如何通过URL获取图片
异步获取图片,通过队列实现,而且图片会有缓存,在下次请求相同的链接时,系统会自动调用缓存,而不从网上请求数据。
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 100.0f, 100.0f, 100.0f)];

    [imageView setImageWithURL:[NSURL URLWithString:@"http://i./r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]];

    [self.view addSubview:imageView];

上面的方法是官方提供的,还有一种方法,

NSURLRequest *request = [NSURLRequest
requestWithURL:[NSURLURLWithString:@"http://www.scott-sherwood.com/wp-content/uploads/2013/01/scene.png"]];

   AFImageRequestOperation
*operation = [AFImageRequestOperationimageRequestOperationWithRequest:request imageProcessingBlock:nilsuccess:^(NSURLRequest*request,
NSHTTPURLResponse*response, UIImage
*image) {
      self.backgroundImageView.image = image;

   } failure:^(NSURLRequest*request, NSHTTPURLResponse*response, NSError
*error) {
      NSLog(@"Error%@",error);
    }];
 
    [operation
start];

如果使用第一种URLWithString:  placeholderImage:会有更多的细节处理,其实实现还是通过AFImageRequestOperation处理,可以点击URLWithString:  placeholderImage:方法进去看一下就一目了然了。所以我觉得还是用第一种好。

如何通过URL获取plist文件
通过url获取plist文件的内容,用的很少,这个方法在官方提供的方法里面没有

   NSString
*weatherUrl =@"http://www.calinks.com.cn/buick/kls/Buickhousekeeper.plist";

   NSURL
*url =[NSURL URLWithString:[weatherUrlstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

   NSURLRequest
*request = [NSURLRequestrequestWithURL:url];

   [AFPropertyListRequestOperationaddAcceptableContentTypes:[NSSet setWithObject:@"text/plain"]];

   AFPropertyListRequestOperation*operation =[AFPropertyListRequestOperationpropertyListRequestOperationWithRequest:request success:^(NSURLRequest
*request, NSHTTPURLResponse
*response, id
propertyList) {
      NSLog(@"%@",(NSDictionary *)propertyList);

       
    }failure:^(NSURLRequest *request,
NSHTTPURLResponse *response,
NSError *error, id propertyList) {
      NSLog(@"%@",error);
    }];
 
    [operation
start];
如果稍不留神,可能就出现ErrorDomain=AFNetworkingErrorDomain Code=-1016 "Expected content type{(
   "application/x-plist"
)}, got text/plain"UserInfo=0x16e91ce0 {NSLocalizedRecoverySuggestion=
 
...
...
,AFNetworkingOperationFailingURLRequestErrorKey= { },NSErrorFailingURLKey=, NSLocalizedDescription=Expected content type{(
   "application/x-plist"
)}, got text/plain,AFNetworkingOperationFailinponseErrorKey= { URL: } { status code: 200, headers {
   "Accept-Ranges" = bytes;
   Connection = "keep-alive";
   "Content-Length" = 974;
   "Content-Type" = "text/plain";
   Date = "Sat, 25 Jan 2014 07:29:26GMT";
   Etag =""1014c2-3ce-4ee63e1c80e00"";
   "Last-Modified" = "Wed, 25 Dec 2013 23:04:24GMT";
   Server = "nginx/1.4.2";
 
} }}
可能还会出现乱码,解决办法就是[AFPropertyListRequestOperation addAcceptableContentTypes:[NSSet setWithObject:@"text/plain"]];

如何通过URL获取XML数据
xml解析使用AFXMLRequestOperation,需要实现苹果自带的NSXMLParserDelegate委托方法,XML中有一些不需要的协议格式内容,所以就不能像json那样解析,还得实现委托。我之前有想过能否所有的XML链接用一个类处理,而且跟服务端做了沟通,结果很不方便,效果不好。XML大多标签不同,格式也不固定,所以就有问题,使用json就要方便的多。
第一步;在.h文件中加入委托NSXMLParserDelegate
第二步;在.m文件方法中加入代码
  
NSURL*url = [NSURLURLWithString:@"http://113.106.90.22:5244/sshopinfo"];

   NSURLRequest
*request = [NSURLRequestrequestWithURL:url];

   AFXMLRequestOperation
*operation =

   [AFXMLRequestOperationXMLParserRequestOperationWithRequest:request success:^(NSURLRequest
*request, NSHTTPURLResponse
*response, NSXMLParser *XMLParser) {
       XMLParser.delegate =
self;

       [XMLParsersetShouldProcessNamespaces:YES];
       [XMLParser
parse];
    }failure:^(NSURLRequest *request,
NSHTTPURLResponse *response,
NSError *error, NSXMLParser *XMLParser) {
      NSLog(@"%@",error);
    }];
    [operation
start];
第三步;在.m文件中实现委托方法
   //在文档开始的时候触发
-(void)parserDidStartDocument:(NSXMLParser *)parser{

   NSLog(@"解析开始!");
}

//解析起始标记
- (void)parser:(NSXMLParser *)parserdidStartElement:(NSString*)elementName
namespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qNameattributes:(NSDictionary*)attributeDict{
   NSLog(@"标记:%@",elementName);

    
}

//解析文本节点
- (void)parser:(NSXMLParser *)parserfoundCharacters:(NSString*)string{
   NSLog(@"值:%@",string);
}

//解析结束标记
- (void)parser:(NSXMLParser *)parserdidEndElement:(NSString*)elementName namespaceURI:(NSString
*)namespaceURIqualifiedName:(NSString*)qName{
   NSLog(@"结束标记:%@",elementName);
}

//文档结束时触发
-(void)parserDidEndDocument:(NSXMLParser *)parser{

   NSLog(@"解析结束!");
}
运行的结果:



如何使用AFHTTPClient进行web service操作
AFHTTPClient处理GET 和POST请求.做网页的朋友们这个方法用的比较多。在要经常调用某个请求时,可以封装,节省资源。

  BaseURLString =@"http://www.raywenderlich.com/downloads/weather_sample/";

   NSURL*baseURL = [NSURLURLWithString:[NSStringstringWithFormat:BaseURLString]];

   NSDictionary
*parameters = [NSDictionarydictionaryWithObject:@"json" forKey:@"format"];

   AFHTTPClient
*client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];

    

   [client registerHTTPOperationClass:[AFJSONRequestOperation class]];

   [client setDefaultHeader:@"Accept" value:@"text/html"];
    [client
postPath:@"weather.php"
parameters:parameters
success:^(AFHTTPRequestOperation *operation,id responseObject) {

       NSString* newStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
      NSLog(@"POST请求:%@",newStr);

   }failure:^(AFHTTPRequestOperation
*operation, NSError
*error) {
      NSLog(@"%@",error);
    }];

    
    [client
getPath:@"weather.php"
parameters:parameters
success:^(AFHTTPRequestOperation *operation,id responseObject) {

       NSString* newStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
      NSLog(@"GET请求:%@",newStr);

   }failure:^(AFHTTPRequestOperation
*operation, NSError
*error) {
      NSLog(@"%@",error);
    }];

运行结果:



如果需要显示网络活动指示器,可以用下面方法:
[AFNetworkActivityIndicatorManager sharedManager].enabled =YES;

Error: Error Domain=AFNetworkingErrorDomain Code=-1016"Request failed: unacceptable content-type: text/html"UserInfo=0x16774de0{NSErrorFailingURLKey=http://192.168.2.2:8181/ecar/tsp/uploadLocation?CID=781666&serviceType=1,AFNetworkingOperationFailinponseErrorKey=
{ URL:http://192.168.2.2:8181/ecar/tsp/uploadLocation?CID=781666&serviceType=1} { status code: 200, headers {


    XXX

 
} }, NSLocalizedDescription=Request failed: unacceptablecontent-type: text/html}

返回数据格式不对。注销这句话: op.responseSerializer= [AFJSONResponseSerializer serializer];然后将返回的数据自己转换。

error = Error Domain=com.alamofire.error.serialization.responseCode=-1016 "Request failed: unacceptable content-type: text/html"UserInfo=0x1740f2c00{com.alamofire.serialization.response.error.response=
{ URL:http://192.168.5.132/api/cats?type=apps } { status code: 200,headers {
    Connection ="keep-alive";
    "Content-Type" = "text/html;charset=utf-8";
    Date = "Thu, 05 Nov 201510:27:42 GMT";
    Server = nginx;
    "Transfer-Encoding" =Identity;
} }

AF可以接受json以外的数据    自己随意定义的格式都可以   只不过要使用AFNetwork提供的解析方法的话  它只对通用的格式做处理   你返回的数据不是那种格式   他就无法解析出来    那要你自己处理   改变AFNetWork的库文件
   找到他判断错误的那个函数   让他从正确的方法返回    如果你不会的话  就在返回错误的方法处理也可以  反正数据已经到了      网络的目的   是为了得到数据   你的数据已经到了  只不过AFNetwork认定你的数据不符合常用的格式     确实也不符合   因为你的数据是加密的东西  而且是对整个json格式加密
  而不是只对值加密   所以要实现这种格式的传输   只能修改AFNetwork的库   而你不会   那就先这么用着

举个例子    你们现在的做法是对整个字符串加密   如果你不这么做   只将值部分加密  而不对键加密   就是{“message”:“值的密文”}  那么这个数据仍然符合json格式  AFNetwork依然能解析出来     
你们对整个json字符串都加密了  那密文就不是json格式了     所以你们可以按我说的改  仅加密值部分    也就按照现在的方法   在错误的返回方法里面处理数据   但是你自己知道数据是正确的  只不过AFNetwork误判了而已       这个属于原理上东西   改不了    要么就是不让AFNetwork解析
    他只透传    你自己解析   如果让他帮你解析  你就要指定一个格式给他    指定了格式 而你的数据不符合格式   那就是按错误的方法返回  
AFNetworking关于HTTP认证的问题

AFNetwork实现basic认证的方法很简单
http://stackoverflow.com/questions/12440059/using-afnetworking-and-http-basic-authentication




AFNetwork实现digest认证





创建一个NSURLCredential对象,然后将对象赋值到请求




https://github.com/AFNetworking/AFNetworking/issues/551

http://stackoverflow.com/questions/31784319/digest-access-authentication-for-afnetworking

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager
manager];
NSURLCredential *credential = [[NSURLCredential alloc]
initWithUser:@"Username" password:@"Password"
persistence:NSURLCredentialPersistenceForSession];
[manager setCredential:credential]; 

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: