青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

羅朝輝(飄飄白云)

關(guān)注嵌入式操作系統(tǒng),移動(dòng)平臺(tái),圖形開發(fā)。-->加微博 ^_^

  C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  85 隨筆 :: 0 文章 :: 169 評(píng)論 :: 0 Trackbacks

深入淺出ObjC消息   

羅朝輝 (http://ww.cppblog.com/kesalin)

轉(zhuǎn)載請(qǐng)注明出處

在入門級(jí)別的ObjC 教程中,我們常對(duì)從C++或Java 或其他面向?qū)ο笳Z言轉(zhuǎn)過來的程序員說,ObjC 中的方法調(diào)用(ObjC中的術(shù)語為消息)跟其他語言中的方法調(diào)用差不多,只是形式有些不同而已。

譬如C++ 中的:

Bird * aBird = new Bird();

aBird->fly();

在ObjC 中則如下:

Bird * aBird = [[Bird alloc] init];

[aBird fly];


乍看起來,好像只是書寫形式不同而已,實(shí)則差異大矣。C++中的方法調(diào)用可能是動(dòng)態(tài)的,也可能是靜態(tài)的;而ObjC中的消息都為動(dòng)態(tài)的。下文將詳細(xì)介紹為什么是動(dòng)態(tài)的,以及編譯器在這背后做了些什么事情。


要說清楚消息這個(gè)話題,我們必須先來了解三個(gè)概念Class, SEL, IMP,它們?cè)趏bjc/objc.h 中定義:

typedef struct objc_class *Class;

typedef struct objc_object {

    Class isa;

} *id;

 

typedef struct objc_selector   *SEL;   

typedef id (*IMP)(id, SEL, ...);

 

Class 的含義

Class 被定義為一個(gè)指向 objc_class的結(jié)構(gòu)體指針,這個(gè)結(jié)構(gòu)體表示每一個(gè)類的類結(jié)構(gòu)。而 objc_class 在objc/objc_class.h中定義如下:

struct objc_class {

    struct objc_class super_class;  /*父類*/

    const char *name;                         /*類名字*/

    long version;                                  /*版本信息*/

    long info;                                        /*類信息*/

    long instance_size;                      /*實(shí)例大小*/

    struct objc_ivar_list *ivars;          /*實(shí)例參數(shù)鏈表*/

    struct objc_method_list **methodLists;  /*方法鏈表*/

    struct objc_cache *cache;                    /*方法緩存*/

    struct objc_protocol_list *protocols;   /*協(xié)議鏈表*/

};

 

由此可見,Class 是指向類結(jié)構(gòu)體的指針,該類結(jié)構(gòu)體含有一個(gè)指向其父類類結(jié)構(gòu)的指針,該類方法的鏈表,該類方法的緩存以及其他必要信息。

NSObject 的class 方法就返回這樣一個(gè)指向其類結(jié)構(gòu)的指針。每一個(gè)類實(shí)例對(duì)象的第一個(gè)實(shí)例變量是一個(gè)指向該對(duì)象的類結(jié)構(gòu)的指針,叫做isa。通過該指針,對(duì)象可以訪問它對(duì)應(yīng)的類以及相應(yīng)的父類。如圖一所示:


 

如圖一所示,圓形所代表的實(shí)例對(duì)象的第一個(gè)實(shí)例變量為 isa,它指向該類的類結(jié)構(gòu) The object’s class。而該類結(jié)構(gòu)有一個(gè)指向其父類類結(jié)構(gòu)的指針superclass, 以及自身消息名稱(selector)/實(shí)現(xiàn)地址(address)的方法鏈表。

 

方法的含義:

注意這里所說的方法鏈表里面存儲(chǔ)的是Method 類型的。圖一中selector 就是指 Method的 SEL,  address就是指Method的 IMP。

 

一個(gè)方法 Method,其包含一個(gè)方法選標(biāo) SEL – 表示該方法的名稱,一個(gè)types – 表示該方法參數(shù)的類型,一個(gè) IMP  - 指向該方法的具體實(shí)現(xiàn)的函數(shù)指針。

Method 在頭文件 objc_class.h中定義如下:

typedef struct objc_method *Method;

typedef struct objc_ method {

    SEL method_name;

    char *method_types;

    IMP method_imp;

};


SEL 的含義:

在前面我們看到方法選標(biāo) SEL 的定義為:

typedef struct objc_selector   *SEL;   

它是一個(gè)指向 objc_selector 指針,表示方法的名字/簽名。如下所示,打印出 selector。

-(NSInteger)maxIn:(NSInteger)a theOther:(NSInteger)b

{

    return (a > b) ? a : b;

}

 

NSLog(@"SEL=%s", @selector(maxIn:theOther:));

 

輸出:SEL=maxIn:theOther:

 

不同的類可以擁有相同的 selector,這個(gè)沒有問題,因?yàn)椴煌惖膶?shí)例對(duì)象performSelector相同的 selector 時(shí),會(huì)在各自的消息選標(biāo)(selector)/實(shí)現(xiàn)地址(address) 方法鏈表中根據(jù) selector 去查找具體的方法實(shí)現(xiàn)IMP, 然后用這個(gè)方法實(shí)現(xiàn)去執(zhí)行具體的實(shí)現(xiàn)代碼。這是一個(gè)動(dòng)態(tài)綁定的過程,在編譯的時(shí)候,我們不知道最終會(huì)執(zhí)行哪一些代碼,只有在執(zhí)行的時(shí)候,通過selector去查詢,我們才能確定具體的執(zhí)行代碼。

IMP 的含義:

在前面我們也看到 IMP 的定義為:

typedef id (*IMP)(id, SEL, ...);

根據(jù)前面id 的定義,我們知道 id是一個(gè)指向 objc_object 結(jié)構(gòu)體的指針,該結(jié)構(gòu)體只有一個(gè)成員isa,所以任何繼承自 NSObject 的類對(duì)象都可以用id 來指代,因?yàn)?NSObject 的第一個(gè)成員實(shí)例就是isa。

至此,我們就很清楚地知道 IMP  的含義:IMP 是一個(gè)函數(shù)指針,這個(gè)被指向的函數(shù)包含一個(gè)接收消息的對(duì)象id(self  指針), 調(diào)用方法的選標(biāo) SEL (方法名),以及不定個(gè)數(shù)的方法參數(shù),并返回一個(gè)id。也就是說 IMP 是消息最終調(diào)用的執(zhí)行代碼,是方法真正的實(shí)現(xiàn)代碼 。我們可以像在C語言里面一樣使用這個(gè)函數(shù)指針。

NSObject 類中的methodForSelector:方法就是這樣一個(gè)獲取指向方法實(shí)現(xiàn)IMP 的指針,methodForSelector:返回的指針和賦值的變量類型必須完全一致,包括方法的參數(shù)類型和返回值類型。

下面的例子展示了怎么使用指針來調(diào)用setFilled:的方法實(shí)現(xiàn):

void (*setter)(id, SEL, BOOL);

int i;

 

setter = (void(*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];

 

for (i = 0; i < 1000; i++)

    setter(targetList[i], @selector(setFilled:), YES);

 

 

使用methodForSelector:來避免動(dòng)態(tài)綁定將減少大部分消息的開銷,但是這只有在指定的消息被重復(fù)發(fā)送很多次時(shí)才有意義,例如上面的for循環(huán)。

注意,methodForSelector:是Cocoa運(yùn)行時(shí)系統(tǒng)的提供的功能,而不是Objective-C語言本身的功能。

 

消息調(diào)用過程:

至此我們對(duì)ObjC 中的消息應(yīng)該有個(gè)大致思路了:示例

Bird * aBird = [[Bird alloc] init];

[aBird fly];

中對(duì) fly 的調(diào)用,編譯器通過插入一些代碼,將之轉(zhuǎn)換為對(duì)方法具體實(shí)現(xiàn)IMP的調(diào)用,這個(gè) IMP是通過在 Bird 的類結(jié)構(gòu)中的方法鏈表中查找名稱為fly 的 選標(biāo)SEL 對(duì)應(yīng)的具體方法實(shí)現(xiàn)找到的。

上面的思路還有一些沒有提及的話題,比如說編譯器插入了什么代碼,如果在方法鏈表中沒有找到對(duì)應(yīng)的 IMP又會(huì)如何,這些話題在下面展開。

 

消息函數(shù) obj_msgSend:

編譯器會(huì)將消息轉(zhuǎn)換為對(duì)消息函數(shù) objc_msgSend的調(diào)用,該函數(shù)有兩個(gè)主要的參數(shù):消息接收者id 和消息對(duì)應(yīng)的方法選標(biāo) SEL, 同時(shí)接收消息中的任意參數(shù):

id objc_msgSend(id theReceiver, SELtheSelector, ...)

如上面的消息 [aBird fly]會(huì)被轉(zhuǎn)換為如下形式的函數(shù)調(diào)用:

objc_msgSend(aBird, @selector(fly));

 

該消息函數(shù)做了動(dòng)態(tài)綁定所需要的一切工作:
1,它首先找到 SEL 對(duì)應(yīng)的方法實(shí)現(xiàn) IMP。因?yàn)椴煌念悓?duì)同一方法可能會(huì)有不同的實(shí)現(xiàn),所以找到的方法實(shí)現(xiàn)依賴于消息接收者的類型。
2, 然后將消息接收者對(duì)象(指向消息接收者對(duì)象的指針)以及方法中指定的參數(shù)傳遞給方法實(shí)現(xiàn) IMP。
3, 最后,將方法實(shí)現(xiàn)的返回值作為該函數(shù)的返回值返回。

編譯器會(huì)自動(dòng)插入調(diào)用該消息函數(shù)objc_msgSend的代碼,我們無須在代碼中顯示調(diào)用該消息函數(shù)。當(dāng)objc_msgSend找到方法對(duì)應(yīng)的實(shí)現(xiàn)時(shí),它將直接調(diào)用該方法實(shí)現(xiàn),并將消息中所有的參數(shù)都傳遞給方法實(shí)現(xiàn),同時(shí),它還將傳遞兩個(gè)隱藏的參數(shù):消息的接收者以及方法名稱 SEL。這些參數(shù)幫助方法實(shí)現(xiàn)獲得了消息表達(dá)式的信息。它們被認(rèn)為是”隱藏“的是因?yàn)樗鼈儾]有在定義方法的源代碼中聲明,而是在代碼編譯時(shí)是插入方法的實(shí)現(xiàn)中的。

盡管這些參數(shù)沒有被顯示聲明,但在源代碼中仍然可以引用它們(就象可以引用消息接收者對(duì)象的實(shí)例變量一樣)。在方法中可以通過self來引用消息接收者對(duì)象,通過選標(biāo)_cmd來引用方法本身。在下面的例子中,_cmd 指的是strange方法,self指的收到strange消息的對(duì)象。

- strange

{

    id target = getTheReceiver();

    SEL method = getTheMethod();

 

    if (target == self || mothod == _cmd)

        return nil;

 

    return [target performSelector:method];

}

 

在這兩個(gè)參數(shù)中,self更有用一些。實(shí)際上,它是在方法實(shí)現(xiàn)中訪問消息接收者對(duì)象的實(shí)例變量的途徑。

 

查找 IMP 的過程:

前面說了,objc_msgSend 會(huì)根據(jù)方法選標(biāo) SEL 在類結(jié)構(gòu)的方法列表中查找方法實(shí)現(xiàn)IMP。這里頭有一些文章,我們?cè)谇懊娴念惤Y(jié)構(gòu)中也看到有一個(gè)叫objc_cache *cache 的成員,這個(gè)緩存為提高效率而存在的。每個(gè)類都有一個(gè)獨(dú)立的緩存,同時(shí)包括繼承的方法和在該類中定義的方法。。

 下面來剖析一段蘋果官方的源碼:

static Method look_up_method(Class cls, SEL sel, BOOL withCache, BOOL withResolver)
{
    Method meth 
= NULL;

    
if (withCache) {
        meth 
= _cache_getMethod(cls, sel, &_objc_msgForward_internal);
        
if (meth == (Method)1) {
            
// Cache contains forward:: . Stop searching.
            return NULL;
        }
    }

    
if (!meth) meth = _class_getMethod(cls, sel);

    
if (!meth  &&  withResolver) meth = _class_resolveMethod(cls, sel);

    
return meth;
}


通過分析上面的代碼,可以看到,查找時(shí):

 

1,首先去該類的方法 cache 中查找,如果找到了就返回它;

2,如果沒有找到,就去該類的方法列表中查找。如果在該類的方法列表中找到了,則將 IMP 返回,并將它加入cache中緩存起來。根據(jù)最近使用原則,這個(gè)方法再次調(diào)用的可能性很大,緩存起來可以節(jié)省下次調(diào)用再次查找的開銷。3,3,如果在該類的方法列表中沒找到對(duì)應(yīng)的 IMP,在通過該類結(jié)構(gòu)中的 super_class指針在其父類結(jié)構(gòu)的方法列表中去查找,直到在某個(gè)父類的方法列表中找到對(duì)應(yīng)的IMP,返回它,并加入cache中;

4,如果在自身以及所有父類的方法列表中都沒有找到對(duì)應(yīng)的 IMP,則看是不是可以進(jìn)行動(dòng)態(tài)方法決議(后面有專文講述這個(gè)話題);

5,如果動(dòng)態(tài)方法決議沒能解決問題,進(jìn)入下面要講的消息轉(zhuǎn)發(fā)流程。

 

 

便利函數(shù):

我們可以通過NSObject的一些方法獲取運(yùn)行時(shí)信息或動(dòng)態(tài)執(zhí)行一些消息:

 class   返回對(duì)象的類;

 isKindOfClass 和 isMemberOfClass檢查對(duì)象是否在指定的類繼承體系中;

 respondsToSelector 檢查對(duì)象能否相應(yīng)指定的消息;

 conformsToProtocol 檢查對(duì)象是否實(shí)現(xiàn)了指定協(xié)議類的方法;

 methodForSelector  返回指定方法實(shí)現(xiàn)的地址。

 performSelector:withObject 執(zhí)行SEL 所指代的方法。

  

消息轉(zhuǎn)發(fā):

通常,給一個(gè)對(duì)象發(fā)送它不能處理的消息會(huì)得到出錯(cuò)提示,然而,Objective-C運(yùn)行時(shí)系統(tǒng)在拋出錯(cuò)誤之前,會(huì)給消息接收對(duì)象發(fā)送一條特別的消息forwardInvocation 來通知該對(duì)象,該消息的唯一參數(shù)是個(gè)NSInvocation類型的對(duì)象——該對(duì)象封裝了原始的消息和消息的參數(shù)。

我們可以實(shí)現(xiàn)forwardInvocation:方法來對(duì)不能處理的消息做一些默認(rèn)的處理,也可以將消息轉(zhuǎn)發(fā)給其他對(duì)象來處理,而不拋出錯(cuò)誤。


關(guān)于消息轉(zhuǎn)發(fā)的作用,可以考慮如下情景:假設(shè),我們需要設(shè)計(jì)一個(gè)能夠響應(yīng)negotiate消息的對(duì)象,并且能夠包括其它類型的對(duì)象對(duì)消息的響應(yīng)。 通過在negotiate方法的實(shí)現(xiàn)中將negotiate消息轉(zhuǎn)發(fā)給其它的對(duì)象來很容易的達(dá)到這一目的。

更進(jìn)一步,假設(shè)我們希望我們的對(duì)象和另外一個(gè)類的對(duì)象對(duì)negotiate的消息的響應(yīng)完全一致。一種可能的方式就是讓我們的類繼承其它類的方法實(shí)現(xiàn)。 然后,有時(shí)候這種方式不可行,因?yàn)槲覀兊念惡推渌惪赡苄枰诓煌睦^承體系中響應(yīng)negotiate消息。

雖然我們的類無法繼承其它類的negotiate方法,但我們?nèi)匀豢梢蕴峁┮粋€(gè)方法實(shí)現(xiàn),這個(gè)方法實(shí)現(xiàn)只是簡(jiǎn)單的將negotiate消息轉(zhuǎn)發(fā)給其他類的對(duì)象,就好像從其它類那兒“借”來的現(xiàn)一樣。如下所示:

- negotiate

{

    if ([someOtherObject respondsToSelector:@selector(negotiate)])

        return [someOtherObject negotiate];

 

    return self;

}

這種方式顯得有欠靈活,特別是有很多消息都希望傳遞給其它對(duì)象時(shí),我們就必須為每一種消息提供方法實(shí)現(xiàn)。此外,這種方式不能處理未知的消息。當(dāng)我們寫下代碼時(shí),所有我們需要轉(zhuǎn)發(fā)的消息的集合都必須確定。然而,實(shí)際上,這個(gè)集合會(huì)隨著運(yùn)行時(shí)事件的發(fā)生,新方法或者新類的定義而變化。

forwardInvocation:消息給這個(gè)問題提供了一個(gè)更特別的,動(dòng)態(tài)的解決方案:當(dāng)一個(gè)對(duì)象由于沒有相應(yīng)的方法實(shí)現(xiàn)而無法響應(yīng)某消息時(shí),運(yùn)行時(shí)系統(tǒng)將通過forwardInvocation:消息通知該對(duì)象。每個(gè)對(duì)象都從NSObject類中繼承了forwardInvocation:方法。然而,NSObject中的方法實(shí)現(xiàn)只是簡(jiǎn)單地調(diào)用了doesNotRecognizeSelector:。通過實(shí)現(xiàn)我們自己的forwardInvocation:方法,我們可以在該方法實(shí)現(xiàn)中將消息轉(zhuǎn)發(fā)給其它對(duì)象。

要轉(zhuǎn)發(fā)消息給其它對(duì)象,forwardInvocation:方法所必須做的有:
1,決定將消息轉(zhuǎn)發(fā)給誰,并且
2,將消息和原來的參數(shù)一塊轉(zhuǎn)發(fā)出去。

消息可以通過invokeWithTarget:方法來轉(zhuǎn)發(fā):

 

- (void) forwardInvocation:(NSInvocation *)anInvocation

{

    if ([someOtherObject respondsToSelector:[anInvocation selector]])

        [anInvocation invokeWithTarget:someOtherObject];

 

    else

        [super forwardInvocation:anInvocation];

}

 

 

轉(zhuǎn)發(fā)消息后的返回值將返回給原來的消息發(fā)送者。您可以將返回任何類型的返回值,包括: id,結(jié)構(gòu)體,浮點(diǎn)數(shù)等。

forwardInvocation:方法就像一個(gè)不能識(shí)別的消息的分發(fā)中心,將這些消息轉(zhuǎn)發(fā)給不同接收對(duì)象。或者它也可以象一個(gè)運(yùn)輸站將所有的消息都發(fā)送給同一個(gè)接收對(duì)象。它可以將一個(gè)消息翻譯成另外一個(gè)消息,或者簡(jiǎn)單的"吃掉“某些消息,因此沒有響應(yīng)也沒有錯(cuò)誤。forwardInvocation:方法也可以對(duì)不同的消息提供同樣的響應(yīng),這一切都取決于方法的具體實(shí)現(xiàn)。該方法所提供是將不同的對(duì)象鏈接到消息鏈的能力。

注意: forwardInvocation:方法只有在消息接收對(duì)象中無法正常響應(yīng)消息時(shí)才會(huì)被調(diào)用。 所以,如果我們希望一個(gè)對(duì)象將negotiate消息轉(zhuǎn)發(fā)給其它對(duì)象,則這個(gè)對(duì)象不能有negotiate方法,也不能在動(dòng)態(tài)方法決議中為之提供實(shí)現(xiàn)。否則,forwardInvocation:將不可能會(huì)被調(diào)用。

參考資料:

Objective-CRuntime Reference:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

Objective-C Runtime Programming Guide:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Introduction/Introduction.html


posted on 2011-08-15 20:20 羅朝輝 閱讀(7991) 評(píng)論(1)  編輯 收藏 引用 所屬分類: 移動(dòng)開發(fā)Cocoa 開發(fā)

評(píng)論

# re: 深入淺出ObjC之消息 [未登錄] 2011-08-15 22:54 chentan
非常好的文章, 燃起了我對(duì)objc學(xué)習(xí)的興趣,謝謝  回復(fù)  更多評(píng)論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精美视频| 亚洲午夜在线视频| 在线观看精品一区| 午夜精品福利视频| 亚洲激情女人| 欧美一区二区三区免费观看视频| 欧美岛国在线观看| 亚洲二区在线| 免费亚洲婷婷| 久久久国产精品亚洲一区| 国产精品亚发布| 亚洲自拍偷拍视频| 一本色道久久综合一区| 欧美欧美全黄| 中文精品视频| 99国产精品久久久久老师| 欧美区国产区| 亚洲午夜一区二区| 亚洲午夜在线| 国产情人综合久久777777| 亚洲欧美一区二区三区极速播放 | 欧美日韩亚洲精品内裤| 91久久精品日日躁夜夜躁国产| 美女脱光内衣内裤视频久久影院| 久久国产欧美| 亚洲国产精品久久| 亚洲精品乱码久久久久久蜜桃麻豆| 欧美激情影音先锋| 一区二区欧美激情| 亚洲一区二区在线看| 国产亚洲精品bv在线观看| 老巨人导航500精品| 美女国产精品| 一本色道久久88综合亚洲精品ⅰ | 亚洲欧美国产另类| 国产精品视频yy9299一区| 亚洲高清三级视频| 欧美视频免费| 欧美在线精品一区| 久久久99免费视频| 亚洲欧洲三级| 亚洲香蕉伊综合在人在线视看| 国产欧美一区二区精品性| 蜜桃av一区二区三区| 欧美精品粉嫩高潮一区二区 | 国产精品青草久久| 欧美专区日韩视频| 久久综合一区| 亚洲一级黄色片| 久久爱www| 亚洲美女在线国产| 午夜亚洲影视| 99精品国产99久久久久久福利| 亚洲天堂成人在线观看| 在线国产精品一区| 亚洲网站在线看| 亚洲国产精品免费| 国产精品99久久久久久人| 在线精品一区| 亚洲欧美日韩久久精品| 亚洲乱码国产乱码精品精 | 国产精品久久精品日日| 欧美bbbxxxxx| 国产农村妇女精品| 亚洲人成人99网站| 一区二区三区在线免费观看 | 牛牛影视久久网| 久久av在线| 欧美日韩亚洲一区二区三区在线| 久久久亚洲影院你懂的| 欧美色网一区二区| 欧美黄色影院| 黑人巨大精品欧美黑白配亚洲| 亚洲精品综合精品自拍| 亚洲高清三级视频| 久久精品一区二区国产| 欧美一区不卡| 国产精品国产三级国产专播精品人 | 欧美韩国日本一区| 国产一区二区高清视频| 99国产精品久久久| 99pao成人国产永久免费视频| 久久精品国产亚洲aⅴ| 欧美亚洲视频在线观看| 欧美午夜片在线观看| 亚洲精品1区2区| 亚洲国产aⅴ天堂久久| 久久精品免视看| 国产一区在线视频| 亚洲影视在线| 欧美日韩伊人| 亚洲激情视频在线播放| 激情亚洲一区二区三区四区| 亚洲欧美精品suv| 亚洲一区二区综合| 欧美日韩另类丝袜其他| 亚洲精品在线观| 亚洲韩国精品一区| 免费成人av在线看| 免费成人黄色片| 亚洲动漫精品| 欧美国产精品v| 亚洲三级视频在线观看| 99国内精品久久| 国产精品久久国产精麻豆99网站| 亚洲色无码播放| 久久av一区二区| 在线电影国产精品| 久久婷婷麻豆| 亚洲二区视频| 日韩网站在线观看| 欧美日韩亚洲综合在线| 亚洲天堂网在线观看| 欧美亚洲免费电影| 国内外成人免费激情在线视频网站| 亚洲欧美色婷婷| 久久久久se| 亚洲精品黄色| 欧美午夜在线观看| 亚洲欧美日本精品| 蜜桃av综合| 99国产精品久久久| 国产精品老牛| 久久久另类综合| 亚洲毛片av| 久久久久久成人| 99国内精品| 一区在线播放| 欧美日韩第一页| 欧美在线一二三区| 亚洲人成77777在线观看网| 欧美一区二区精品| 1024亚洲| 国产精品区一区二区三| 久久久久久久久久看片| 99精品福利视频| 久久综合一区| 一区二区三区国产在线观看| 国产在线日韩| 欧美色网一区二区| 麻豆国产va免费精品高清在线| 一本久久综合亚洲鲁鲁| 美女诱惑一区| 午夜精品视频在线观看| 亚洲国产欧美日韩| 国产精品性做久久久久久| 欧美精品久久99| 久久一二三区| 久久国产精品久久久久久| 亚洲最新视频在线| 亚洲第一毛片| 免费h精品视频在线播放| 午夜国产精品视频| 亚洲视频你懂的| 狠狠色噜噜狠狠色综合久| 欧美激情视频网站| 久久婷婷蜜乳一本欲蜜臀| 亚洲午夜国产一区99re久久 | 欧美在线观看一区二区| 免费在线观看日韩欧美| 国产精品每日更新| 欧美国产视频一区二区| 欧美主播一区二区三区美女 久久精品人| 亚洲激情欧美激情| 欧美黄网免费在线观看| 久久综合国产精品| 午夜天堂精品久久久久| 日韩午夜电影在线观看| 狠狠久久亚洲欧美| 国产欧美日韩另类一区| 欧美性猛交xxxx乱大交蜜桃| 欧美承认网站| 欧美电影免费观看| 欧美国产在线观看| 欧美激情一区二区三区在线视频| 久久综合色88| 久久一区二区三区av| 久久噜噜噜精品国产亚洲综合 | 狠狠色综合色区| 国产在线日韩| 国产午夜精品一区理论片飘花| 欧美午夜精品久久久久久久| 欧美人牲a欧美精品| 欧美猛交免费看| 欧美日韩一级视频| 欧美性大战久久久久久久| 国产精品欧美日韩一区二区| 国产精品日日做人人爱| 国产精品网红福利| 国产三级精品三级| 激情六月婷婷久久| 亚洲黄色av| 一本久道久久久| 亚洲制服av| 久久av一区二区三区| 免费欧美在线视频| 亚洲黄色成人久久久| 夜夜夜久久久| 羞羞视频在线观看欧美| 久久久精彩视频|