標籤:
http網路程式庫是集XML解析,Json解析,網狀圖片下載,plist解析,資料流請求操作,上傳,下載,緩衝等網路眾多功能於一身的強大的類庫。最新版本支援session,xctool單元測試。網路擷取資料一直是手機軟體的重中之重,如果處理的不好,會造成很差的使用者體驗。隨著ASIHTTPRequest的停止更新,更換網路程式庫是必然的事情,AFNetworking就是很好的替代品。而且都是輕量級,不要擔心加入太多庫會多軟體效能有影響。1.為什麼用第三方網路程式庫?先說如果不用網路程式庫,我曾有一次覺得什麼都用蘋果原生的好,XML解析用蘋果內建的委託,下載圖片自己寫,如果你也有跟我一樣的經曆,那你會發現自己管理起來很複雜,很容易出錯。而且效能不好。如果你是一個追求完美的人,那就放下你的固執,就如當初的我一樣,嘗試一下網路程式庫吧。2.為什麼要用AFNetworking?第一點,它有人更新和維護,而且目前使用者很多,第二點,還是使用者很多,那麼他的資料,文檔,demo就多,很好找遇到問題好解決。如果不用AFNetworking,還有一種MKNetworkKit也不錯,不妨一試。
如何選擇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。
如何通過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
如何通過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:request imageProcessingBlock: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:方法進去看一下就一目瞭然了。所以我覺得還是用第一種好。
如何通過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"]];
如何通過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(@"解析結束!");
}
啟動並執行結果:
如何使用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,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, 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 = [AFJSONResponseSerializerserializer];然後將返回的資料自己轉換。
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解析 他只透傳 你自己解析 如果讓他幫你解析 你就要指定一個格式給他 指定了格式 而你的資料不符合格式 那就是按錯誤的方法返回
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的使用