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

iOS开发网络数据之AFNetworking使用

2016-07-19 16:21 477 查看
http网络库是集XML解析,Json解析,网络图片下载,plist解析,数据流请求操作,上传,下载,缓存等网络众多功能于一身的强大的类库。最新版本支持session,xctool单元测试。网络获取数据一直是手机软件的重中之重,如果处理的不好,会造成很差的用户体验。随着ASIHTTPRequest的停止更新,更换网络库是必然的事情,AFNetworking就是很好的替代品。而且都是轻量级,不要担心加入太多库会多软件性能有影响。


1.为什么用第三方网络库?

先说如果不用网络库,我曾有一次觉得什么都用苹果原生的好,XML解析用苹果自带的委托,下载图片自己写,如果你也有跟我一样的经历,那你会发现自己管理起来很复杂,很容易出错。而且性能不好。如果你是一个追求完美的人,那就放下你的固执,就如当初的我一样,尝试一下网络库吧。


2.为什么要用AFNetworking?

第一点,它有人更新和维护,而且目前使用者很多,第二点,还是使用者很多,那么他的资料,文档,demo就多,很好找遇到问题好解决。如果不用AFNetworking,还有一种MKNetworkKit也不错,不妨一试。


3.如何选择AFNetworking版本

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

AFNetworking 2.0的下载地址https://github.com/AFNetworking/AFNetworking

如果你想要兼容IOS5或MAC OS X 10.7,那你需要用最新发布的1.x版本

AFNetworking 1.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。


4.如何通过URL获取json数据

第一种,利用AFJSONRequestOperation,官方网站上给的例子:

    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];

    //    从URL获取json数据

    AFJSONRequestOperation *operation1
= [AFJSONRequestOperation JSONRequestOperationWithRequest:requestsuccess:^(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
= [[AFHTTPRequestOperation alloc] initWithRequest:request];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{

        NSString *html = operation.responseString;

             NSData*
data=[html dataUsingEncoding:NSUTF8StringEncoding];

             id dict=[NSJSONSerialization  JSONObjectWithData:data options:0 error:nil];

        NSLog(@"获取到的数据为:%@",dict);

    }failure:^(AFHTTPRequestOperation *operation, NSError *error)
{

        NSLog(@"发生错误!%@",error);

    }];

    NSOperationQueue *queue
= [[NSOperationQueue alloc] init];

    [queue addOperation:operation];

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


5.如何通过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:[NSURL URLWithString:@"http://www.scott-sherwood.com/wp-content/uploads/2013/01/scene.png"]];

    AFImageRequestOperation *operation
= [AFImageRequestOperation imageRequestOperationWithRequest:requestimageProcessingBlock:nil success:^(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:方法进去看一下就一目了然了。所以我觉得还是用第一种好。


6.如何通过URL获取plist文件

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

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

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

    NSURLRequest *request
= [NSURLRequest requestWithURL:url];

    [AFPropertyListRequestOperation addAcceptableContentTypes:[NSSet
setWithObject:@"text/plain"]];

    AFPropertyListRequestOperation *operation
= [AFPropertyListRequestOperation propertyListRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList)
{

        NSLog(@"%@",(NSDictionary *)propertyList);

        

    }failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList)
{

        NSLog(@"%@",error);

    }];

 

    [operation start];

如果稍不留神,可能就出现Error
Domain=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:26 GMT";

    Etag = ""1014c2-3ce-4ee63e1c80e00"";

    "Last-Modified" = "Wed, 25 Dec 2013 23:04:24 GMT";

    Server = "nginx/1.4.2";

 

} }}

可能还会出现乱码,解决办法就是[AFPropertyListRequestOperation addAcceptableContentTypes:[NSSet setWithObject:@"text/plain"]];


7.如何通过URL获取XML数据

xml解析使用AFXMLRequestOperation,需要实现苹果自带的NSXMLParserDelegate委托方法,XML中有一些不需要的协议格式内容,所以就不能像json那样解析,还得实现委托。我之前有想过能否所有的XML链接用一个类处理,而且跟服务端做了沟通,结果很不方便,效果不好。XML大多标签不同,格式也不固定,所以就有问题,使用json就要方便的多。

第一步;在.h文件中加入委托NSXMLParserDelegate

第二步;在.m文件方法中加入代码

    NSURL *url
= [NSURL URLWithString:@"http://113.106.90.22:5244/sshopinfo"];

    NSURLRequest *request
= [NSURLRequest requestWithURL:url];

    AFXMLRequestOperation *operation
=

    [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request success:^(NSURLRequest *request,NSHTTPURLResponse *response, NSXMLParser *XMLParser)
{

        XMLParser.delegate = self;

        [XMLParser setShouldProcessNamespaces: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 *)parser
didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{

    NSLog(@"标记:%@",elementName);

    

}

//解析文本节点

- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string{

    NSLog(@"值:%@",string);

}

//解析结束标记

- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName{

    NSLog(@"结束标记:%@",elementName);

}

//文档结束时触发

-(void) parserDidEndDocument:(NSXMLParser *)parser{

    NSLog(@"解析结束!");

}

运行的结果

8.如何使用AFHTTPClient进行web service操作

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

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

    NSURL *baseURL
= [NSURL URLWithString:[NSString stringWithFormat:BaseURLString]];

    NSDictionary *parameters
= [NSDictionary dictionaryWithObject:@"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, idresponseObject)
{

        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, idresponseObject)
{

        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: unacceptable content-type: text/html}

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

error = Error Domain=com.alamofire.error.serialization.response Code=-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 2015 10:27:42 GMT";

    Server = nginx;

    "Transfer-Encoding" = Identity;

} }

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

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

 


9.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]; 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios AFNetWorking 数据