精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深度解析Cocoa異步請(qǐng)求和libxml2.dylib教程

移動(dòng)開發(fā) iOS
本文介紹的是深度解析Cocoa異步請(qǐng)求和libxml2.dylib教程,,主要介紹了cocoa異步請(qǐng)求的過程,先來看詳細(xì)內(nèi)容。

深度解析Cocoa異步請(qǐng)求libxml2.dylib教程是本文要介紹的內(nèi)容,不多說,直接進(jìn)入話題,很早就在cocoachina上看到這個(gè)框架了,今天終于有機(jī)會(huì)來使用這個(gè)東東了.

我這里寫一下,如何往iphone項(xiàng)目中添加這個(gè)框架.

步驟如下:

1.下載該framework : http://github.com/pokeb/asi-http-request/tree

2.將class根目錄下的文件全拷貝到自己的項(xiàng)目中,另外還要在 External/Reachability/下將其中的Reachability.h/m

也拷貝到自己的項(xiàng)目中.

3.添加需要的framework.可以參考 http://allseeing-i.com/ASIHTTPRequest/Setup-instructions

需要額外添加的有: CFNetwork.framework, MobileCoreServices.framework,SystemConfiguration.framework,libz.1.2.3.dylib,libxml2.dylib

然后運(yùn)行項(xiàng)目,會(huì)發(fā)現(xiàn)有很多xml相關(guān)的error,不用急,這時(shí)因?yàn)閘ibxml2.dylib這個(gè)framework(這個(gè)框架不是很friendly,我們還需要做一些工作).

在xcode中project->edit project settings->然后search "search paths",然后在path中添加 /usr/include/libxml2

這樣就ok了,可以根據(jù)官方的教程來學(xué)習(xí)了.

http://allseeing-i.com/ASIHTTPRequest/How-to-use

我下了一個(gè)sample code  XMLPerformance 解析xml,我建了一個(gè)工程照著上面做,但是編譯時(shí)提示錯(cuò)誤,

  1. error libxml/tree.h: No such file or directory 

我立刻想到?jīng)]有add Frameworks ,我把libsqlite3.dylib 和 libxml2.dylib都加進(jìn)去了,但是還是報(bào)錯(cuò)。

  1. error libxml/tree.h: No such file or directory  
  2. An error on the .h is a compile-time error with your Header Search Paths, not a .dylib or a linker error.  
  3. You have to ensure that /usr/include/libxml2 is in your Header Search Paths in your Release configuration。 

在iphone開發(fā)中,異步操作是一個(gè)永恒的話題,尤其當(dāng)iphone手機(jī)需要和遠(yuǎn)程服務(wù)器進(jìn)行交互時(shí),使用異步請(qǐng)求是很普遍的做法。

通常,這需要NSURLConnection和NSOperation結(jié)合起來使用。這方面的資料網(wǎng)絡(luò)上自然有不少的介紹,不過要找一個(gè)能運(yùn)行的代碼也并不容易。許多文章介紹的并不全面,或者使用了過時(shí)的SDK,在新IOS版本下并不適用(當(dāng)前***的ios是4.2了)。這些代碼很經(jīng)典,但仍然很容易使人誤入歧途。

本文總結(jié)了眾多文檔介紹的方法和代碼,揭示了異步操作中的實(shí)現(xiàn)細(xì)節(jié)和初學(xué)者(包括筆者)易犯的錯(cuò)誤,使后來者少走彎路。

一、使用NSOperation實(shí)現(xiàn)異步請(qǐng)求

1、新建類,繼承自NSOperation。

  1. @interface URLOperation : NSOperation  
  2. {  
  3.     NSURLRequest*  _request;  
  4.     NSURLConnection* _connection;  
  5.     NSMutableData* _data;  
  6.     //構(gòu)建gb2312的encoding  
  7.     NSStringEncoding enc;  
  8. }  
  9. - (id)initWithURLString:(NSString *)url;  
  10. @property (readonly) NSData *data;  
  11. @end 

接口部分不多做介紹,我們來看實(shí)現(xiàn)部分。

首先是帶一個(gè)NSString參數(shù)的構(gòu)造函數(shù)。在其中初始化成員變量。

其中enc是 NSStringEncoding 類型,因?yàn)榉?wù)器返回的字符中使用了中文,所以我們通過它指定了一個(gè)gb2312的字符編碼。

許多資料中說,需要在NSOperation中重載一個(gè)叫做isConcurrent的函數(shù)并在其中返回YES,否則不支持異步執(zhí)行。但是實(shí)際上,我們?cè)谶@里注釋了這個(gè)重載方法,程序也沒有報(bào)任何錯(cuò)誤,其執(zhí)行方式依然是異步的。

  1. @implementation URLOperation  
  2. @synthesize data=_data;  
  3. - (id)initWithURLString:(NSString *)url {  
  4.     if (self = [self init]) {  
  5.         NSLog(@"%@",url);  
  6.         _request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:url  
  7.         //構(gòu)建gb2312的encoding  
  8.         enc =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);  
  9.         _data = [[NSMutableData data] retain];  
  10.     }  
  11.     return self;  
  12. }  
  13. - (void)dealloc {  
  14.     [_request release],_request=nil;  
  15.     [_data release],_data=nil;  
  16.     [_connection release],_connection=nil;  
  17.     [super dealloc];  
  18. }  
  19. // 如果不重載下面的函數(shù),異步方式調(diào)用會(huì)出錯(cuò)  
  20. //- (BOOL)isConcurrent {  
  21. //  return YES;//返回yes表示支持異步調(diào)用,否則為支持同步調(diào)用  
  22. //} 

整個(gè)類中最重要的方法是start方法。Start是NSOperation類的主方法,主方法的叫法充分說明了其重要性,因?yàn)檫@個(gè)方法執(zhí)行完后,該NSOperation的執(zhí)行線程就結(jié)束了(返回調(diào)用者的主線程),同時(shí)對(duì)象實(shí)例就會(huì)被釋放,也就意味著你定義的其他代碼(包括delegate方法)也不會(huì)被執(zhí)行。很多資料中的start方法都只有最簡單的一句(包括“易飛揚(yáng)的博客 “的博文):

  1. [NSURLConnection connectionWithRequest:_request delegate:self]; 

如果這樣的話,delegate方法沒有執(zhí)行機(jī)會(huì)。因?yàn)閟tart方法結(jié)束后delegate(即self對(duì)象)已經(jīng)被釋放了,delegate的方法也就無從執(zhí)行。

所以在上面的代碼中,還有一個(gè)while循環(huán),這個(gè)while循環(huán)的退出條件是http連接終止(即請(qǐng)求結(jié)束)。當(dāng)循環(huán)結(jié)束,我們的工作也就完成了。

  1. // 開始處理-本類的主方法  
  2. - (void)start {  
  3.     if (![self isCancelled]) {  
  4.         NSLog(@"start operation");  
  5.         // 以異步方式處理事件,并設(shè)置代理  
  6.         _connection=[[NSURLConnection connectionWithRequest:_request delegate:self]retain];  
  7.         //下面建立一個(gè)循環(huán)直到連接終止,使線程不離開主方法,否則connection的delegate方法不會(huì)被調(diào)用,因?yàn)橹鞣椒ńY(jié)束對(duì)象的生命周期即終止  
  8.         //這個(gè)問題參考 http://www.cocoabuilder.com/archive/cocoa/279826-nsurlrequest-and-nsoperationqueue.html  
  9.         while(_connection != nil) {  
  10.             [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];     
  11.         }  
  12.     }  

接下來,是NSURLConnection的delegate方法,這部分的代碼和大部分資料的介紹是一樣的,你可以實(shí)現(xiàn)全部的delegate方法,但這里我們只實(shí)現(xiàn)其中3個(gè)就足夠了,其余的方法不用理會(huì)。如你所見,你可以在其中添加自己想到的任何代碼,包括接收數(shù)據(jù),進(jìn)行字符編碼或者做xml解析。

  1. #pragma mark NSURLConnection delegate Method  
  2. // 接收到數(shù)據(jù)(增量)時(shí)  
  3. - (void)connection:(NSURLConnection*)connection  
  4.     didReceiveData:(NSData*)data {  
  5.     NSLog(@"connection:");  
  6.     NSLog(@"%@",[[NSString alloc] initWithData:data encoding:enc]);  
  7.     // 添加數(shù)據(jù)  
  8.  
  9.     [_data appendData:data];  
  10.  
  11. }  
  12. // HTTP請(qǐng)求結(jié)束時(shí)  
  13. - (void)connectionDidFinishLoading:(NSURLConnection*)connection {  
  14.     [_connection release],_connection=nil;  
  15.     //NSLog(@"%@",[[NSString alloc] initWithData:_data encoding:enc]);  
  16. }  
  17. -(void)connection: (NSURLConnection *) connection didFailWithError: (NSError *) error{  
  18.     NSLog(@"connection error");  
  19. }  
  20. @end 

到此,雖然代碼還沒有完成,但我們已經(jīng)可以運(yùn)行它了。你可以看到console輸出的內(nèi)容,觀察程序的運(yùn)行狀態(tài)。

2、調(diào)用NSOperation

我們的NSOperation類可以在ViewController中調(diào)用,也可以直接放在AppDelegate中進(jìn)行。

在這里,我是通過點(diǎn)擊按鈕來觸發(fā)調(diào)用代碼的:

  1. -(void)loginClicked{  
  2.     //構(gòu)造登錄請(qǐng)求url  
  3.     NSString* url=@”http://google.com”;  
  4.     _queue = [[NSOperationQueue alloc] init];  
  5.     URLOperation* operation=[[URLOperation alloc ]initWithURLString:url];  
  6.     // 開始處理  
  7.     [_queue addOperation:operation];  
  8.     [operation release];//隊(duì)列已對(duì)其retain,可以進(jìn)行release;  

_queue是一個(gè) NSOperationQueue 對(duì)象,當(dāng)往其中添加 NSOperation 對(duì)象后, NSOperation 線程會(huì)被自動(dòng)執(zhí)行(不是立即執(zhí)行,根據(jù)調(diào)度情況)。

3、KVO編程模型

我們的NSOperation完成了向服務(wù)器的請(qǐng)求并將服務(wù)器數(shù)據(jù)下載到成員變量_data中了。現(xiàn)在的問題是,由于這一切是通過異步操作進(jìn)行的,我們無法取得_data中的數(shù)據(jù),因?yàn)槲覀儾恢朗裁磿r(shí)候異步操作完成,以便去訪問_data屬性(假設(shè)我們將_data定義為屬性了),取得服務(wù)器數(shù)據(jù)。

我們需要一種機(jī)制,當(dāng)NSOperation完成所有工作之后,通知調(diào)用線程。

這里我們想到了KVO編程模型(鍵-值觀察模型)。這是cocoa綁定技術(shù)中使用的一種設(shè)計(jì)模式,它可以使一個(gè)對(duì)象在屬性值發(fā)生變化時(shí)主動(dòng)通知另一個(gè)對(duì)象并觸發(fā)相應(yīng)的方法。

首先,我們?cè)贜SOperation的子類中添加一個(gè)BOOL變量,當(dāng)這個(gè)變量變?yōu)閅ES時(shí),標(biāo)志異步操作已經(jīng)完成:

  1. BOOL _isFinished; 

在實(shí)現(xiàn)中加入這個(gè)變量的訪問方法:

  1. - (BOOL)isFinished  
  2. {  
  3.     return _isFinished;  

cocoa的KVO模型中,有兩種通知觀察者的方式,自動(dòng)通知和手動(dòng)通知。顧名思義,自動(dòng)通知由cocoa在屬性值變化時(shí)自動(dòng)通知觀察者,而手動(dòng)通知需要在值變化時(shí)調(diào)用 willChangeValueForKey:和didChangeValueForKey: 方法通知調(diào)用者。為求簡便,我們一般使用自動(dòng)通知。

要使用自動(dòng)通知,需要在 automaticallyNotifiesObserversForKey方法中明確告訴cocoa,哪些鍵值要使用自動(dòng)通知:

  1. //重新實(shí)現(xiàn)NSObject類中的automaticallyNotifiesObserversForKey:方法,返回yes表示自動(dòng)通知。  
  2. + (BOOL):(NSString*)key  
  3. {  
  4.     //當(dāng)這兩個(gè)值改變時(shí),使用自動(dòng)通知已注冊(cè)過的觀察者,觀察者需要實(shí)現(xiàn)observeValueForKeyPath:ofObject:change:context:方法  
  5.     if ([key isEqualToString:@"isFinished"])  
  6.     {  
  7.         return YES;  
  8.     }  
  9.     return [super automaticallyNotifiesObserversForKey:key];  

然后,在需要改變_isFinished變量的地方,使用

  1. [self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"]; 

方法,而不是僅僅使用簡單賦值。

我們需要在3個(gè)地方改變isFinished值為YES,請(qǐng)求結(jié)束時(shí)、連接出錯(cuò)誤,線程被cancel。請(qǐng)?jiān)趯?duì)應(yīng)的方法代碼中加入上面的語句。

***,需要在觀察者的代碼中進(jìn)行注冊(cè)。打開ViewController中調(diào)用NSOperation子類的地方,加入:

  1.     //kvo注冊(cè)  
  2.     [operation addObserver:self forKeyPath:@"isFinished"  
  3.                    options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:operation];  
  4. 并實(shí)現(xiàn) observeValueForKeyPath 方法:  
  5. //接收變更通知  
  6. - (void)observeValueForKeyPath:(NSString *)keyPath  
  7.                       ofObject:(id)object  
  8.                        change:(NSDictionary *)change  
  9.                        context:(void *)context  
  10. {  
  11.     if ([keyPath isEqual:@"isFinished"]) {  
  12.         BOOL isFinished=[[change objectForKey:NSKeyValueChangeNewKey] intValue];  
  13.         if (isFinished) {//如果服務(wù)器數(shù)據(jù)接收完畢  
  14.             [indicatorView stopAnimating];  
  15.             URLOperation* ctx=(URLOperation*)context;  
  16.             NSStringEncoding enc=CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);  
  17.             NSLog(@"%@",[[NSString alloc] initWithData:[ctx data] encoding:enc]);  
  18.             //取消kvo注冊(cè)  
  19.             [ctx removeObserver:self  
  20.                     forKeyPath:@"isFinished"];  
  21.         }        
  22.     }else{  
  23.         // be sure to call the super implementation  
  24.         // if the superclass implements it  
  25.         [super observeValueForKeyPath:keyPath  
  26.                              ofObject:object  
  27.                                change:change  
  28.                               context:context];  
  29.     }  

運(yùn)行程序,查看控制臺(tái)的輸出。

#p#

4、libxml的sax解析接口

iphone和服務(wù)器交互通常使用xml數(shù)據(jù)交換格式,因此本文中也涉及到了xml文件解析的問題。有許多有名氣的xml解析器可供我們選擇,如: BXML,TouchXML,KissXML,TinyXML的第三方庫和GDataXML。

Xml解析分為兩類,一類是DOM解析,一類為SAX解析。前者如GDataXML,解析過程中需要建立文檔樹,操作XML元素時(shí)通過樹形結(jié)構(gòu)進(jìn)行導(dǎo)航。DOM解析的特點(diǎn)是便于程序員理解xml文檔樹結(jié)構(gòu),API 的使用簡單;缺點(diǎn)是速度較SAX解析慢,且內(nèi)存開銷較大。在某些情況下,比如iphone開發(fā),受制于有限的內(nèi)存空間(一個(gè)應(yīng)用最多可用10幾m的內(nèi)存), DOM解析無法使用(當(dāng)然,在模擬器上是沒有問題的)。

libxml2的是一個(gè)開放源碼庫,默認(rèn)情況下iPhone SDK 中已經(jīng)包括在內(nèi)。它是一個(gè)基于C的API,所以在使用上比cocoa的 NSXML要麻煩許多(一種類似c函數(shù)的使用方式),但是該庫同時(shí)支持DOM和SAX解析,其解析速度較快,而且占用內(nèi)存小,是最適合使用在iphone上的解析器。從性能上講,所有知名的解析器中,TBXML最快,但在內(nèi)存占用上,libxml使用的內(nèi)存開銷是最小的。因此,我們決定使用libxml的sax接口。

首先,我們需要在project中導(dǎo)入framework:libxml2.dylib。

雖然libxml是sdk中自帶的,但它的頭文件卻未放在默認(rèn)的地方,因此還需要我們?cè)O(shè)置project的build選項(xiàng):HEADER_SEARCH_PATHS = /usr/include/libxml2,否則libxml庫不可用。

然后,我們就可以在源代碼中 #import <libxml/tree.h> 了。

假設(shè)我們要實(shí)現(xiàn)這樣的功能:有一個(gè)登錄按鈕,點(diǎn)擊后將用戶密碼帳號(hào)發(fā)送http請(qǐng)求到服務(wù)器(用上文中介紹的異步請(qǐng)求技術(shù)),服務(wù)器進(jìn)行驗(yàn)證后以xml文件方式返回驗(yàn)證結(jié)果。我們要用libxml的sax方式將這個(gè)xml文件解析出來。

服務(wù)器返回的xml文件格式可能如下:

<?xml version="1.0" encoding="GB2312" standalone="no" ?>

<root>

<login_info>

<login_status>true</login_status>

</login_info>

<List>

        <system Name=xxx Path=xxx ImageIndex=xxx>

……

</List>

</root>


其中有我們最關(guān)心的1個(gè)元素:login_status 。

如果login_status返回false,說明登錄驗(yàn)證失敗,否則,服務(wù)器除返回login_status外,還會(huì)返回一個(gè)list元素,包含了一些用戶的數(shù)據(jù),這些數(shù)據(jù)是<system>元素的集合。

整個(gè)實(shí)現(xiàn)步驟見下。

首先,實(shí)現(xiàn)一個(gè)超類, 這個(gè)超類是一個(gè)抽象類,許多方法都只是空的,等待subclass去實(shí)現(xiàn)。

其中有3個(gè)方法與libxml的sax接口相關(guān),是sax解析過程中的3個(gè)重要事件的回調(diào)方法,分別是元素的開始標(biāo)記、元素體(開始標(biāo)記和結(jié)束標(biāo)記之間的文本)、結(jié)束標(biāo)記。Sax中有許多的事件,但絕大部分時(shí)間,我們只需要處理這3個(gè)事件。因?yàn)楹芏鄷r(shí)候,我們只會(huì)對(duì)xml文件中的元素屬性和內(nèi)容感興趣,而通過這3個(gè)事件已經(jīng)足以使我們讀取到xml節(jié)點(diǎn)的屬性和內(nèi)容。

而成員變量中,_root變量是比較關(guān)鍵的,它以dictionary的形式保存了解析結(jié)果,因?yàn)槿魏蝬ml文檔的根節(jié)點(diǎn)都是root,所以無論什么樣子的xml文件,都可以放在這個(gè)_root 中。

因此我們?yōu)?_root 變量提供了一個(gè)訪問方法getResult,等xml解析結(jié)束,可以通過這個(gè)方法訪問_root。

  1. #import <Foundation/Foundation.h> 
  2. #import <libxml/tree.h> 
  3. @interface BaseXmlParser : NSObject {  
  4.     NSStringEncoding enc;  
  5.     NSMutableDictionary*    _root;  
  6. }  
  7. // Property  
  8. - (void)startElementLocalName:(const xmlChar*)localname  
  9.                        prefix:(const xmlChar*)prefix  
  10.                           URI:(const xmlChar*)URI  
  11.                 nb_namespaces:(int)nb_namespaces  
  12.                    namespaces:(const xmlChar**)namespaces  
  13.                 nb_attributes:(int)nb_attributes  
  14.                  nb_defaulted:(int)nb_defaultedslo  
  15.                    attributes:(const xmlChar**)attributes;  
  16. - (void)endElementLocalName:(const xmlChar*)localname  
  17.                      prefix:(const xmlChar*)prefix URI:(const xmlChar*)URI;  
  18. - (void)charactersFound:(const xmlChar*)ch  
  19.                     len:(int)len;  
  20. -(NSDictionary*)getResult;  
  21. @end  
  22. #import "BaseXmlParser.h"  
  23. @implementation BaseXmlParser  
  24. // Property  
  25.  
  26. -(id)init{  
  27.     if(self=[super init]){  
  28.         //構(gòu)建gb2312的encoding  
  29.         enc =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);  
  30.         _root=[[NSMutableDictionary alloc]init];  
  31.     }  
  32.     return self;  
  33. }  
  34. -(void)dealloc{  
  35.     [_root release],_root=nil;  
  36.     [super dealloc];  
  37. }  
  38.  
  39. #pragma mark -- libxml handler,主要是3個(gè)回調(diào)方法--  
  40.  
  41. //解析元素開始標(biāo)記時(shí)觸發(fā),在這里取元素的屬性值  
  42. - (void)startElementLocalName:(const xmlChar*)localname  
  43.                        prefix:(const xmlChar*)prefix  
  44.                           URI:(const xmlChar*)URI  
  45.                 nb_namespaces:(int)nb_namespaces  
  46.                    namespaces:(const xmlChar**)namespaces  
  47.                 nb_attributes:(int)nb_attributes  
  48.                  nb_defaulted:(int)nb_defaultedslo  
  49.                    attributes:(const xmlChar**)attributes  
  50. {    
  51. }  
  52. //解析元素結(jié)束標(biāo)記時(shí)觸發(fā)  
  53. - (void)endElementLocalName:(const xmlChar*)localname  
  54.                      prefix:(const xmlChar*)prefix URI:(const xmlChar*)URI  
  55. {  
  56. }  
  57. //解析元素體時(shí)觸發(fā)  
  58. - (void)charactersFound:(const xmlChar*)ch  
  59.                     len:(int)len  
  60. {  
  61. }  
  62. //返回解析結(jié)果  
  63. -(NSDictionary*)getResult{  
  64.     return _root;  
  65. }  
  66. @end 

現(xiàn)在我們需要擴(kuò)展這個(gè)BaseXmlParser,并重載其中的3個(gè)sax方法。

該子類除了重載父類的3個(gè)方法外,還增加了幾個(gè)成員變量。其中flag是一個(gè)int類型,用于sax解析的緣故,解析過程中需要合適的標(biāo)志變量,用于標(biāo)志當(dāng)前處理到的元素標(biāo)記。為了簡單起見,我們沒有為每一個(gè)標(biāo)記都設(shè)立一個(gè)標(biāo)志,而是統(tǒng)一使用一個(gè)int標(biāo)志,比如flag為1時(shí),表示正在處理login_status標(biāo)記,為2時(shí),表示正在處理system標(biāo)記。

回顧前面的xml文件格式,我們其實(shí)只關(guān)心兩種標(biāo)記,login_status標(biāo)記和system標(biāo)記。Login_status標(biāo)記沒有屬性,但它的元素體是我們關(guān)心的;而system標(biāo)記則相反,它并沒有元素體,但我們需要它的屬性值。

這是一個(gè)很好的例子。因?yàn)樗瑫r(shí)展示了屬性的解析和元素體的解析。瀏覽整個(gè)類的代碼,我們總結(jié)出3個(gè)sax事件的使用規(guī)律是:

如果要讀取元素屬性,需要在“元素開始標(biāo)記讀取”事件(即 startElementLocalName 方法)中處理;

如果要讀取元素體文本,則在“元素體讀取”事件(即 charactersFound方法)中處理;

#p#

在“元素標(biāo)記讀取”事件( 即endElementLocalName 方法)中,則進(jìn)行標(biāo)志變量的改變/歸零。

  1. #import <Foundation/Foundation.h> 
  2.  
  3. #import <libxml/tree.h> 
  4.  
  5. #import "BaseXmlParser.h"  
  6.  
  7. @interface DLTLoginParser : BaseXmlParser {  
  8.  
  9.     int flag;  
  10.  
  11.     NSMutableDictionary*    _currentItem;    
  12.  
  13. }
  14.  
  15. - (void)startElementLocalName:(const xmlChar*)localname  
  16.                        prefix:(const xmlChar*)prefix  
  17.                           URI:(const xmlChar*)URI  
  18.                 nb_namespaces:(int)nb_namespaces  
  19.                    namespaces:(const xmlChar**)namespaces  
  20.                 nb_attributes:(int)nb_attributes  
  21.                 nb_defaulted:(int)nb_defaultedslo   
  22.                    attributes:(const xmlChar**)attributes;  
  23.  
  24. - (void):(const xmlChar*)localname  
  25.  
  26.                      prefix:(const xmlChar*)prefix URI:(const xmlChar*)URI;  
  27.  
  28. - (void)charactersFound:(const xmlChar*)ch  
  29.  
  30.                     len:(int)len;  
  31.  
  32. @end  
  33. #import "DLTLoginParser.h"  
  34. @implementation DLTLoginParser  
  35. -(id)init{  
  36.     if(self=[super init]){  
  37.         NSMutableArray* items=[[NSMutableArray alloc]init];
  38.         [_root setObject:items forKey:@"items"];  
  39.         [items release];//已被_root持有了,可以釋放
  40.     }
  41.     return self;  
  42. }  
  43.  
  44. -(void)dealloc{  
  45.     [_currentItem release],_currentItem=nil;  
  46.     [super dealloc];  
  47. }  
  48.  
  49. //--------------------------------------------------------------//  
  50.  
  51. #pragma mark -- libxml handler,主要是3個(gè)回調(diào)方法--  
  52.  
  53. //--------------------------------------------------------------//  
  54.  
  55. //解析元素開始標(biāo)記時(shí)觸發(fā),在這里取元素的屬性值  
  56. - (void)startElementLocalName:(const xmlChar*)localname  
  57.                        prefix:(const xmlChar*)prefix  
  58.                           URI:(const xmlChar*)URI  
  59.                 nb_namespaces:(int)nb_namespaces  
  60.                    namespaces:(const xmlChar**)namespaces  
  61.                 nb_attributes:(int)nb_attributes  
  62.                  nb_defaulted:(int)nb_defaultedslo  
  63.                    attributes:(const xmlChar**)attributes  
  64. {  
  65.     // login_status,置標(biāo)志為1  
  66.     if (strncmp((char*)localname, "login_status", sizeof("login_status")) == 0) {  
  67.         flag=1;  
  68.         return;  
  69.     }  
  70.     // system,置標(biāo)志為2  
  71.     if (strncmp((char*)localname, "system", sizeof("system")) == 0) {  
  72.         flag=2;  
  73.         _currentItem = [NSMutableDictionary dictionary];  
  74.         //查找屬性  
  75.         NSString *key,*val;  
  76.         for (int i=0; i<nb_attributes; i++){  
  77.             key = [NSString stringWithCString:(const char*)attributes[0] encoding:NSUTF8StringEncoding];  
  78.             val = [[NSString alloc] initWithBytes:(const void*)attributes[3] length:(attributes[4] - attributes[3]) 
  79. encoding:NSUTF8StringEncoding];  
  80.             NSLog(@"key=%@,val=%@",key,val);  
  81.             if ([@"Name" isEqualToString:key]) {  
  82.                 [_currentItem setObject:val forKey:@"name"];  
  83.                 break;  
  84.             }  
  85.             // [val release];  
  86.             attributes += 5;//指針移動(dòng)5個(gè)字符串,到下一個(gè)屬性  
  87.         }  
  88.         [[_root objectForKey:@"items"] addObject:_currentItem];  
  89.         return;  
  90.     }  
  91. }  
  92. //解析元素結(jié)束標(biāo)記時(shí)觸發(fā)  
  93. - (void)endElementLocalName:(const xmlChar*)localname  
  94.                      prefix:(const xmlChar*)prefix URI:(const xmlChar*)URI  
  95. {  
  96.     flag=0;//標(biāo)志歸零  
  97. }  
  98. //解析元素體時(shí)觸發(fā)  
  99. - (void)charactersFound:(const xmlChar*)ch  
  100.                     len:(int)len  
  101. {  
  102.     // 取login_status元素體  
  103.     if (flag==1) {  
  104.         NSString*   string;  
  105.         string = [[NSString alloc] initWithBytes:ch length:len encoding:NSUTF8StringEncoding];  
  106.         [_root setObject:string forKey:@"login_status"];  
  107.         NSLog(@"login_status:%@",string);  
  108.     }  
  109. }  
  110. @end 

接下來,改造我們的異步請(qǐng)求操作類URLOperation。首先在interface中增加

兩個(gè)變量:

  1. xmlParserCtxtPtr  _parserContext; //Xml解析器指針  
  2. BaseXmlParser* baseParser; //Xml解析器 

其中第1個(gè)變量(一個(gè)結(jié)構(gòu)體)的聲明顯得有點(diǎn)奇怪,似乎是跟第2個(gè)變量混淆了。這是因?yàn)閘ibxml是一個(gè)c函數(shù)庫,其函數(shù)調(diào)用仍然使用一種面向結(jié)構(gòu)的編程風(fēng)格。所以我們?cè)诤竺孢€會(huì)看到一些結(jié)構(gòu)體似的變量。

另外,把_data成員的類型從NSMutableData改變?yōu)镹SMutableDictionary,并把它配置為屬性,因?yàn)槲覀兊恼?qǐng)求結(jié)果應(yīng)當(dāng)被xml解析器解析為dictionary了:

  1. @property (nonatomic,retain) NSDictionary *data; 

當(dāng)然,記住為它提供訪問方法:

  1. @synthesize data=_data

然后,更改 initWithURLString 構(gòu)造方法,為其增加一個(gè)名為 xmlParser 的參數(shù)

  1. - (id)initWithURLString:(NSString *)url xmlParser:(BaseXmlParser*)parser{  
  2.     if (self = [super init]) {  
  3.         baseParser=[parser retain];  
  4.         NSLog(@"%@",url);  
  5.         _request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:url]];//[[NSURLRequest requestWithURL:[NSURL URLWithString:url]]retain];  
  6.         //構(gòu)建gb2312的encoding  
  7.         enc =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);  
  8.         _data = [[NSMutableData data] retain];  
  9.     }  
  10.     return self;  

在start方法中,我們可以這樣創(chuàng)建一個(gè)xml解析器指針:

// 創(chuàng)建XML解析器指針

  1. _parserContext = xmlCreatePushParserCtxt(&_saxHandlerStruct, baseParser, NULL, 0, NULL); 

注意第2個(gè)參數(shù)就是具體實(shí)現(xiàn)了sax解析的xml解析器。這個(gè)解析器對(duì)象是通過構(gòu)造函數(shù)“注入”的。

而***個(gè)參數(shù)是一個(gè)結(jié)構(gòu)體指針 xmlSAXHandler 結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體我們定義為靜態(tài)變量(注意把定義放在@implementation⋯⋯@end之外):

//libxml的xmlSAXHandler結(jié)構(gòu)體定義,凡是要實(shí)現(xiàn)的handler函數(shù)都寫在這里,不準(zhǔn)備實(shí)現(xiàn)的用null代替。一般而言,我們只實(shí)現(xiàn)其中3個(gè)就夠了

  1. static xmlSAXHandler _saxHandlerStruct = {  
  2.     NULL,             
  3.     NULL,            
  4.     NULL,             
  5.     NULL,             
  6.     NULL,             
  7.     NULL,             
  8.     NULL,             
  9.     NULL,             
  10.     NULL,             
  11.     NULL,             
  12.     NULL,             
  13.     NULL,             
  14.     NULL,             
  15.     NULL,             
  16.     NULL,             
  17.     NULL,             
  18.     NULL,             
  19.     charactersFoundHandler,  
  20.     NULL,             
  21.     NULL,             
  22.     NULL,             
  23.     NULL,             
  24.     NULL,             
  25.     NULL,             
  26.     NULL,             
  27.     NULL,             
  28.     NULL,             
  29.     XML_SAX2_MAGIC,   
  30.     NULL,             
  31.     startElementHandler,     
  32.     endElementHandler,       
  33.     NULL,             
  34. }; 

機(jī)構(gòu)體中填入了我們準(zhǔn)備實(shí)現(xiàn)的3個(gè)方法句柄,因此我們還應(yīng)當(dāng)定義這3個(gè)方法。由于結(jié)構(gòu)體是靜態(tài)的,只能訪問靜態(tài)成員,所以這3個(gè)方法也是靜態(tài)的:

  1. //3個(gè)靜態(tài)方法的實(shí)現(xiàn),其實(shí)是調(diào)用了參數(shù)ctx的成員方法, ctx在_parserContext初始化時(shí)傳入  
  2. static void startElementHandler(  
  3.                                 void* ctx,  
  4.                                 const xmlChar* localname,  
  5.                                 const xmlChar* prefix,  
  6.                                 const xmlChar* URI,  
  7.                                 int nb_namespaces,  
  8.                                 const xmlChar** namespaces,  
  9.                                 int nb_attributes,  
  10.                                 int nb_defaulted,  
  11.                                 const xmlChar** attributes)  
  12. {  
  13.     [(BaseXmlParser*)ctx  
  14.      startElementLocalName:localname  
  15.      prefix:prefix URI:URI  
  16.      nb_namespaces:nb_namespaces  
  17.      namespaces:namespaces  
  18.      nb_attributes:nb_attributes  
  19.      nb_defaulted:nb_defaulted  
  20.      attributes:attributes];  
  21. }  
  22. static void endElementHandler(  
  23.                               void* ctx,  
  24.                               const xmlChar* localname,  
  25.                               const xmlChar* prefix,  
  26.                              const xmlChar* URI)  
  27.  
  28. {  
  29.     [(BaseXmlParser*)ctx  
  30.      endElementLocalName:localname  
  31.      prefix:prefix  
  32.      URI:URI];  
  33. }  
  34. static void charactersFoundHandler(  
  35.                                    void* ctx,  
  36.                                    const xmlChar* ch,  
  37.                                    int len)  
  38. {  
  39.     [(BaseXmlParser*)ctx  
  40.      charactersFound:ch len:len];  

其實(shí)這3個(gè)靜態(tài)方法只是調(diào)用了超類BaseXmlParser的成員方法,他的具體類型依賴于ctx的注入類型,也就是說,這里的ctx可以是任何BaseXmlParser的子類。 實(shí)際使用中,我們應(yīng)該注入其子類,從而可以根據(jù)不同的情況為URLOperation“注入”不同的解析器,實(shí)現(xiàn)解析不同的xml文件的目的。

現(xiàn)在,需要把解析器應(yīng)用到NSURLConnection的委托方法中(這里省略了部分代碼,只列出了新增加的部分):

  1. #pragma mark NSURLConnection delegate Method  
  2. // 接收到數(shù)據(jù)(增量)時(shí)  
  3. - (void)connection:(NSURLConnection*)connection  
  4.     didReceiveData:(NSData*)data {  
  5.     // 使用libxml解析器進(jìn)行xml解析  
  6.     xmlParseChunk(_parserContext, (const char*)[data bytes], [data length], 0);  
  7.          ⋯⋯  
  8. }  
  9. // HTTP請(qǐng)求結(jié)束時(shí)  
  10. - (void)connectionDidFinishLoading:(NSURLConnection*)connection {  
  11.              if(baseParser!=nil && baseParser!=NULL){  
  12.         [self setData:[[NSDictionary alloc] initWithDictionary:[baseParser getResult]]];  
  13.     }else {  
  14.         NSLog(@"baseparser is nil");  
  15.     }  
  16.     // 添加解析數(shù)據(jù)(結(jié)束),注意***一個(gè)參數(shù)termindate  
  17.     xmlParseChunk(_parserContext, NULL, 0, 1);  
  18.     // 釋放XML解析器  
  19.     if (_parserContext) {  
  20.         xmlFreeParserCtxt(_parserContext), _parserContext = NULL;  
  21.     }  
  22. ⋯⋯  
  23. }  
  24.  
  25. -(void)connection: (NSURLConnection *) connection didFailWithError: (NSError *) error{  
  26.     // 釋放XML解析器  
  27.     if (_parserContext) {  
  28.         xmlFreeParserCtxt(_parserContext), _parserContext = NULL;  
  29.     }  
  30.          ⋯⋯  
  31. }  
  32. @end 

接下來,在“登錄”按鈕中代碼也要做相應(yīng)的修改,因?yàn)閁RLOperation的構(gòu)造函數(shù)要求傳遞一個(gè)具體的xml解析器對(duì)象:

  1. //構(gòu)造xmlparser  
  2. DLTLoginParser* parser=[[DLTLoginParser alloc]init];  
  3. URLOperation* operation=[[URLOperation alloc ]initWithURLString:url xmlParser:parser];  
  4. [parser release]; 

然后,在接收變更通知方法中打印解析結(jié)果:

  1. URLOperation* ctx=(URLOperation*)context;  
  2. NSLog(@"%@",[ctx data]); 

后臺(tái)打印結(jié)果:

  1. {  
  2.     items =     (  
  3.                 {  
  4.             name = "\U4e91\U7535\U4f01\U4fe1\U901a";  
  5.         },  
  6.                 {  
  7.             name = "\U79fb\U52a8\U8c03\U5ea6";  
  8.         },  
  9.                 {  
  10.             name = "\U79fb\U52a8\U62a2\U4fee";  
  11.         }  
  12.     );  
  13.     "login_status" = true;  

小結(jié):深度解析Cocoa異步請(qǐng)求libxml2.dylib教程的內(nèi)容介紹完了,希望本文對(duì)你有所幫助!

責(zé)任編輯:zhaolei 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2011-08-10 18:37:32

CocoaMac OS X

2024-07-31 15:57:41

2024-10-15 10:28:43

2020-01-02 16:30:02

Spring BootJava異步請(qǐng)求

2013-12-09 10:34:12

2020-10-09 08:29:24

POSTGET參數(shù)

2011-07-20 10:12:33

XCode Cocoa dylib

2011-05-11 17:48:31

CocoaiOS

2024-05-28 00:00:20

ElasticseaJava開發(fā)

2011-07-18 16:51:51

Cocoa 單態(tài) 模式

2011-07-26 15:14:24

蘋果 Cocoa 內(nèi)存

2011-07-26 10:42:00

Cocoa Cocoa2d 游戲

2011-07-07 09:54:01

Cocoa Core Foundation

2011-08-11 15:46:55

CocoaCocoa Touch框架

2011-07-29 16:08:31

Objective-C 內(nèi)存

2025-05-12 01:33:00

異步函數(shù)Promise

2021-02-17 09:09:15

異步請(qǐng)求

2011-07-07 13:51:24

Cocoa 框架

2011-05-11 15:27:58

Windows OOPCocoa MVCCocoa

2011-08-10 19:33:09

Cocoa對(duì)象
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

精品免费视频| 99青草视频在线播放视| 亚洲免费激情| 国产亚洲人成a一在线v站| 五月天av在线播放| 免费影视亚洲| 国产女同性恋一区二区| 成人做爽爽免费视频| 日本高清www免费视频| 日韩精品第一区| 亚洲激情久久久| 激情黄色小视频| 色偷偷偷在线视频播放| 日韩理论片网站| 欧美日韩精品免费看| 国产视频第二页| 久久综合导航| 久久久日本电影| 91av手机在线| 精品高清久久| 亚洲精品v欧美精品v日韩精品| 国产精品自拍视频在线| 亚洲综合电影| 亚洲成a人片在线观看中文| 图片区小说区区亚洲五月| 成人午夜福利视频| 国产福利亚洲| 国产美女诱惑一区二区| 日韩中文字幕在线观看| 女~淫辱の触手3d动漫| 韩国精品福利一区二区三区| 欧美精品粉嫩高潮一区二区| 国产精品无码一本二本三本色| 第一中文字幕在线| 亚洲一区在线电影| 国产手机视频在线观看| 欧美激情黑人| 欧美国产日韩亚洲一区| 欧美高清性xxxxhd| 免费a在线观看| 91麻豆swag| 久久精精品视频| 香蕉久久一区二区三区| 不卡的电视剧免费网站有什么| 91入口在线观看| 国产毛片毛片毛片毛片毛片| 韩国女主播成人在线观看| 91精品国产综合久久久久久久久| 亚洲精品毛片一区二区三区| 久久久久一区| 国产精品视频内| 亚洲天堂免费av| 麻豆精品精品国产自在97香蕉| 国产精品久久久久久av福利| 亚洲精品一区二区二区| 麻豆成人免费电影| 成人精品一区二区三区| 国产日韩欧美一区二区东京热 | 91专区在线观看| 日本不卡影院| 精品国产91久久久久久| 自慰无码一区二区三区| 久久精品女人天堂av免费观看| 日韩欧美中文字幕在线观看| 成年人小视频网站| 成人国产一区| 欧美一级欧美一级在线播放| 国产伦理在线观看| 日韩av网址大全| 国产亚洲成av人片在线观看桃| 国产伦理片在线观看| 日本一区二区高清不卡| 久久国产色av| 日本少妇xxxx动漫| 丝袜a∨在线一区二区三区不卡| 国产精品青草久久久久福利99| 亚洲熟妇av乱码在线观看| 国产黑丝在线一区二区三区| 国产精品国模大尺度私拍| 亚洲色大成网站www| 中文在线一区二区| 欧美日韩视频免费| 欧美日韩尤物久久| 日韩一区二区免费在线电影| 91玉足脚交白嫩脚丫| 欧州一区二区| 久久久久久国产精品美女| 国产日韩欧美中文| 乱h高h女3p含苞待放| 亚洲激情网址| 国产免费一区二区三区香蕉精| 亚洲国产精品二区| 久久影院午夜片一区| 精品国产一区二区三区在线| 欧美大胆a人体大胆做受| 欧美日韩免费观看一区二区三区| 亚洲国产精品第一页| 精品国内自产拍在线观看视频| 久久中文字幕视频| 国产精品熟女视频| 东方欧美亚洲色图在线| 图片区小说区区亚洲五月| av福利在线导航| 欧美喷潮久久久xxxxx| 一起草在线视频| 亚洲mv大片欧洲mv大片| 日韩免费在线播放| 黑人精品一区二区| 亚洲欧美色一区| 日本精品久久久久中文字幕| 中文字幕av一区二区三区四区| 国产午夜一区二区| 五月婷婷激情网| 国产在线精品一区二区不卡了 | 亚洲天堂成人| 成人免费自拍视频| 国产一区二区三区福利| 亚洲成人第一页| 中文字幕第一页在线视频| 中日韩免视频上线全都免费| 久久久久久有精品国产| 国产精品伊人久久| 中文字幕免费观看一区| 毛片av免费在线观看| 日韩av网站在线免费观看| 欧美人与性动交| 国产毛片毛片毛片毛片| 国产精品国产自产拍在线| 亚洲精品高清无码视频| 亚洲日产av中文字幕| 97在线免费视频| 成人免费观看在线视频| 亚洲狠狠爱一区二区三区| 三日本三级少妇三级99| 国产精品二区不卡| 国产男女猛烈无遮挡91| 69久久夜色| 欧美亚洲禁片免费| 一级特黄曰皮片视频| 巨乳诱惑日韩免费av| 美女精品国产| 中文字幕影音在线| 亚洲欧美成人网| 免费看日批视频| 久久久精品免费免费| 无码无遮挡又大又爽又黄的视频| 日本成人a网站| 91精品国产高清久久久久久久久| 涩涩视频免费看| 性欧美大战久久久久久久久| 男女一区二区三区| 国产一区二区三区的电影 | 国产成人午夜| 日韩一区二区在线免费观看| 国产一区二区视频在线观看免费| 国内精品国产成人| 国产成人一二三区| 久久精品66| 日本精品视频在线观看| 成人在线观看黄色| 欧美精品 日韩| 劲爆欧美第一页| 成人国产电影网| 青青在线视频免费| 欧美大黑bbbbbbbbb在线| 91在线|亚洲| 2021天堂中文幕一二区在线观| 亚洲裸体xxxx| 夜夜嗨av禁果av粉嫩avhd| 亚洲精品国产高清久久伦理二区| 日本一区二区免费视频| 亚洲精品影视| 无码免费一区二区三区免费播放| 97久久精品一区二区三区的观看方式| 欧美日韩国产91| 欧美拍拍视频| 9191精品国产综合久久久久久| 国产精品视频一区二区三| 成人晚上爱看视频| 国产精品igao| 国产精品多人| 欧美亚洲爱爱另类综合| 亚洲一区有码| 欧美性猛交xxxx乱大交退制版| 国产精品一区二区性色av| 国模精品一区二区| 日韩三级在线免费观看| 国产午夜性春猛交ⅹxxx| 中文乱码免费一区二区 | 91香蕉国产在线观看软件| 九九热免费在线观看| 一区在线视频观看| 亚洲精品在线视频观看| 久久免费视频66| 国产欧美在线看| 在线观看v片| 色综合久久天天综线观看| 国产精品麻豆一区二区三区| 精品少妇一区二区三区日产乱码 | 国产午夜亚洲精品理论片色戒 | 国产视频不卡一区| 操人视频免费看| 99精品视频免费看| 国产精品国产三级国产aⅴ原创 | 国产精品福利av| 波多野结衣视频播放| 激情文学综合丁香| 成人精品视频一区二区| 伊人久久婷婷| 中文字幕第一页亚洲| 国产精品一区高清| 久久精品国产一区二区三区不卡| 国产不卡精品在线| 国产成人高清激情视频在线观看| xxx在线免费观看| 欧美乱大交xxxxx另类电影| 999国产在线视频| 日韩国产中文字幕| 欧美综合视频在线| 日韩午夜中文字幕| 国产一区二区在线视频观看| 91成人国产精品| 色屁屁影院www国产高清麻豆| 亚洲午夜久久久| 日韩欧美国产成人精品免费| 中文一区二区完整视频在线观看| 精品国产av无码| av动漫一区二区| 国产a级黄色片| 成人免费观看视频| 不许穿内裤随时挨c调教h苏绵| 国产一区三区三区| aaa一级黄色片| 久久精品国产99国产| 黄大色黄女片18第一次| 日本欧美一区二区在线观看| 97公开免费视频| 丝袜美腿亚洲色图| 冲田杏梨av在线| 免费欧美在线视频| 色乱码一区二区三区在线| 蜜桃视频在线观看一区| 中文字幕在线综合| 久久精品国产精品青草| 91亚洲一区二区| 国产不卡一区视频| 水蜜桃av无码| 久久精品日韩一区二区三区| 中文字幕网站在线观看| 日本一区二区成人| 无码人妻精品中文字幕 | 精品不卡一区二区| 在线欧美一区二区| 在线免费观看一级片| 欧美疯狂做受xxxx富婆| av一区二区三| 日韩av最新在线| 国产免费av在线| www.日韩av.com| 亚洲妇熟xxxx妇色黄| 欧美激情小视频| 手机在线理论片| 国产成人免费av电影| 亚洲精品大全| 国产成人精品免费视频大全最热| 日本国产精品| 亚洲一区二区三区涩| 欧美激情91| 欧美激情视频免费看| 久久中文在线| 亚洲欧美日韩网站| 99久久久精品| 懂色av粉嫩av浪潮av| 亚洲精品欧美激情| 美日韩一二三区| 欧美区视频在线观看| 人妻一区二区三区| 国产亚洲一区二区在线| а√天堂8资源在线官网| 久久人人爽国产| 91大神在线观看线路一区| 69174成人网| 猛男gaygay欧美视频| 色撸撸在线观看| 羞羞视频在线观看欧美| www.五月天色| 久久网站最新地址| 青青操视频在线播放| 在线精品观看国产| 性欧美18一19性猛交| 国产性猛交xxxx免费看久久| 五月婷婷深爱五月| 日本欧美在线观看| 熟妇高潮一区二区| 国产精品久久久久影院老司| 国产午夜福利精品| 欧美日韩一区二区电影| 四虎永久在线精品免费网址| 日韩中文字幕视频| 在线看片福利| 国产精品我不卡| 国产精品成人av| 国内外免费激情视频| 成人av免费网站| 国产精品成人69xxx免费视频| 色综合天天综合网国产成人综合天 | 国产jizzjizz一区二区| 国产精品国产三级国产专业不| 亚洲丰满少妇videoshd| 国产精品丝袜黑色高跟鞋| 国产一区二区激情| 欧美裸体视频| 高清国产一区| 欧美在线不卡| 亚洲午夜精品一区| 国产日韩欧美在线一区| 日韩欧美成人一区二区三区| 日韩免费一区二区三区在线播放| 亚洲成人影院麻豆| 国产福利精品在线| 亚洲免费成人av在线| 欧美不卡在线播放| 国产成a人亚洲| 激情综合网五月天| 欧美mv和日韩mv的网站| 亚洲精品白浆| 成人性色av| 亚洲天堂免费| 在线成人免费av| 亚洲卡通动漫在线| 国产成人av免费看| 欧美精品做受xxx性少妇| 国产精品久久久久久久久久辛辛 | 18aaaa精品欧美大片h| 国产成人精品一区二区三区福利 | 亚洲人成7777| 国产精品久久久久久久久久久久久久久久| 中文字幕无线精品亚洲乱码一区| 日本欧美韩国| 亚洲午夜精品久久久久久浪潮| 免费成人av在线| 国产一级淫片久久久片a级| 欧美日韩一区二区在线观看视频 | 69视频在线播放| 日韩av黄色在线| 91av俱乐部| 国产精品国产自产拍高清av王其 | 国产高清精品软男同| 欧美日韩123区| 亚洲激情另类| 亚洲欧美偷拍另类| 亚洲视频一区在线观看| va婷婷在线免费观看| 九九热这里只有精品免费看| 成人精品毛片| 国产又黄又大又粗视频| 国产色婷婷亚洲99精品小说| 日韩精品极品视频在线观看免费| 久热国产精品| 小嫩苞一区二区三区| 日韩精品中文字幕在线一区| 国产va在线视频| 欧美日韩国产一二| 麻豆国产精品一区二区三区 | 成人乱色短篇合集| 一区二区在线| 中文字幕乱码在线| 欧美午夜不卡在线观看免费| 色呦呦在线观看视频| 九九九九精品| 美女视频第一区二区三区免费观看网站| 天天色天天综合| 亚洲成人xxx| 精品免费av一区二区三区| 最新中文字幕久久| 91影院在线免费观看| 国产又大又黑又粗| 性色av香蕉一区二区| 免费a级毛片在线观看| 日韩午夜精品视频| 免费看男女www网站入口在线| 欧美精品一区二区三区在线四季| 久久电影国产免费久久电影| av资源吧首页| 中文字幕日韩欧美在线| 国产精品xxx在线观看| 向日葵污视频在线观看| 五月婷婷久久综合| 69xxxx欧美| 久久综合九色欧美狠狠| 国内精品伊人久久久久av影院| 黄色片视频网站| 久久五月天色综合| 一道本一区二区三区| 欧美69精品久久久久久不卡| 欧美亚洲一区二区在线观看| 黄色激情在线播放| 日韩精品一区二区三区电影| 久久精品夜色噜噜亚洲aⅴ| xxxwww在线观看|