亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

iOS開發之GCD基礎

2019-11-14 20:23:06
字體:
來源:轉載
供稿:網友

重新回顧、學習GCD、Block。先貼出一篇不錯的講解GCD基礎使用的文章

原文地址:http://blog.csdn.net/aolan1108/article/details/17283415

 

 

做了2年的ios開發,很想靜下心來想想,做一些總結,但是苦于生活和工作方面的種種原因,一直沒能如愿。今天終于下定決心,把自己所學所想記錄下來,方便以后查看,同時可供大家分享。

 
就像之前說的,做了兩年的ios開發,只知道不斷的copy代碼,如果你要真的問我GCD是神馬東東,我一時半會也說不清楚。這里我要為自己生存在互聯網時代感覺到慶幸,我在網上翻閱了很多資料,大都不太完整,在這些資料中,我不斷篩選,終于把GCD給整明白了。我不喜歡說官方的話,說一個東西,從他的定義開始,這個比較俗套,如果大家真的不明白GCD是啥意思,可以自己找去。
 
隊列種類:
一、主線程的Main queue,通過dispatch_get_main_queue獲取。
二、并行隊列global dispatch queue,通過dispatch_get_global_queue獲取,由系統創建(不需要開發人員去創建)三個不同優先級的dispatch queue。并行隊列的執行順序與其加入隊列的順序相同。
三、串行隊列serial queues一般用于按順序同步訪問,可創建任意數量的串行隊列,各個串行隊列之間是并發的。一般用dispatch_queue_create來進行創建,非arc的情況下需要用戶手動來釋放隊列,可能會有人說,既然隊列也是一種對象,可以創建和釋放,那一定會有引用計數器了,是的,可以使用函數dispatch_retain和dispatch_release來增加或者減少引用計數器。
 
提交job:
在舉例子給大家看之前,我還想說說兩種提交job的方式:dispatch_async和dispatch_sync,分別是異步執行和同步執行,兩者之前的區別在于,前者在把任務提交到隊列執行不會造成阻塞,而后者后面的代碼塊需要等到隊列中的任務執行完成后才可以執行。
 
下面是例子
 
例子一,我們可以看到首先執行的是第二條打印語句,這說明這條語句沒有被阻塞。
 
[objc] view plaincopy
 
  1. //主線程異步執行  -(void)action1{                    dispatch_async(dispatch_get_main_queue(), ^{                    for (int i = 0; i< 5; i++) NSLog(@"主線程異步執行===========%d",i);                            });                    NSLog(@"=================主線程異步執行");      }  

     



打印結果:
 

2013-12-09 14:36:20.863 TestGCD[872:a0b] =================主線程異步執行

2013-12-09 14:36:20.864 TestGCD[872:a0b] 主線程異步執行===========0

2013-12-09 14:36:20.865 TestGCD[872:a0b] 主線程異步執行===========1

2013-12-09 14:36:20.865 TestGCD[872:a0b] 主線程異步執行===========2

2013-12-09 14:36:20.865 TestGCD[872:a0b] 主線程異步執行===========3

2013-12-09 14:36:20.866 TestGCD[872:a0b] 主線程異步執行===========4

 
 
 
 
 
例子二,會有人問,既然主線程可以異步執行,那么主線程也可以同步執行嘍。的確是可以的,但是不能直接在action1里面將dispatch_async改為dispatch_sync,這樣修改是沒有意義的,大家可以試試,里面的任務根本不會執行。
 
[objc] view plaincopy
 
  1. //主線程同步執行  -(void)action2{            dispatch_async(dispatch_get_global_queue(0, 0), ^{                    for (int i = 0; i< 3; i++) NSLog(@"并發線程異步執行===========%d",i);                    dispatch_sync(dispatch_get_main_queue(), ^{                            for (int i = 0; i< 3; i++) NSLog(@"主線程同步執行===========%d",i);                        });                     NSLog(@"===========主線程執行完畢");      });             NSLog(@"===========并發線程可能正在執行");  }  

     

打印結果:

 

2013-12-09 15:22:22.352 TestGCD[1269:a0b] ===========并發線程可能正在執行

2013-12-09 15:22:22.352 TestGCD[1269:1403] 并發線程異步執行===========0

2013-12-09 15:22:22.355 TestGCD[1269:1403] 并發線程異步執行===========1

2013-12-09 15:22:22.356 TestGCD[1269:1403] 并發線程異步執行===========2

2013-12-09 15:22:22.357 TestGCD[1269:a0b] 主線程同步執行===========0

2013-12-09 15:22:22.358 TestGCD[1269:a0b] 主線程同步執行===========1

2013-12-09 15:22:22.358 TestGCD[1269:a0b] 主線程同步執行===========2

2013-12-09 15:22:22.359 TestGCD[1269:1403] ===========主線程執行完畢

 

從結果中我們仔細理解,就會比較深刻,首先我們看到打印語句4最先執行(有可能不是最先執行,這個是由系統決定的),說明我們提交到并發隊列dispatch_get_global_queue的執行方式是異步的;其次打印語句2是在打印語句1執行完才開始執行,這說明dispatch_get_global_queue雖然是并發隊列,但是其內部的任務執行順序是串行的;最后,我們看到打印語句3是在打印語句2執行完成后再執行,說明主線程同步執行是阻塞的,我們通常會將UI的刷新用同步方式放到主線程中去操作,當然這種操作的時間一般都比較短,以至于用戶幾乎無法察覺。

 

例子三,其實GCD的操作真正的意義當然不在于在主線程中做一些操作,在很多時候,我們都會用到后臺線程,如果你的iphone是多核的cpu,那么恭喜你,你可以有流暢的操作體驗,即使不是多核,你的操作體驗也相對流暢,因為你可以將需要大量時間才能執行完成的任務放到后臺線程中去執行,用戶就不會有死機感,譬如說圖片加載、網絡請求、復雜邏輯的數據解析等等。

 

//后臺異步執行  
-(void)action3{            dispatch_async(dispatch_get_global_queue(0, 0), ^{                    for (int i = 0; i< 10000; i++) NSLog(@"=================%d",i);                });            NSLog(@"=================后臺異步執行");  } 

 

 

你可以迅速點擊兩次按鈕,即連續執行兩次action3方法,在這里,我們截取部分打印結果:

 

 

2013-12-09 15:51:30.864 TestGCD[1350:3007] =================0

2013-12-09 15:51:30.864 TestGCD[1350:a0b] =================后臺異步執行

2013-12-09 15:51:30.864 TestGCD[1350:3007] =================1

2013-12-09 15:51:30.865 TestGCD[1350:3007] =================2

2013-12-09 15:51:30.865 TestGCD[1350:3007] =================3

......

 

2013-12-09 15:51:31.007 TestGCD[1350:3007] =================600

2013-12-09 15:51:31.007 TestGCD[1350:3007] =================601

2013-12-09 15:51:31.007 TestGCD[1350:a0b] =================后臺異步執行

2013-12-09 15:51:31.007 TestGCD[1350:3007] =================602

2013-12-09 15:51:31.008 TestGCD[1350:3007] =================603

2013-12-09 15:51:31.007 TestGCD[1350:473] =================0

2013-12-09 15:51:31.008 TestGCD[1350:473] =================1

2013-12-09 15:51:31.008 TestGCD[1350:473] =================2

2013-12-09 15:51:31.008 TestGCD[1350:3007] =================604

2013-12-09 15:51:31.008 TestGCD[1350:473] =================3

2013-12-09 15:51:31.008 TestGCD[1350:3007] =================605

......

 

我們看到由于action3被執行了兩次,在點擊第一次后,屏幕仍然接受點擊時間,說明主線程沒有被阻塞,用戶體驗仍然很流暢。兩次點擊實際上是提交了兩個任務到dispatch_get_global_queue隊列上,第一次任務并沒有執行完成,第二次任務就開始執行,說明dispatch_get_global_queue是并行隊列,即任務塊與任務塊之間是并發執行的。

 

 

 

例子四,肯定會有小伙伴們說后臺既然可以異步執行,那么應該也可以同步執行嘍,是的,你是對的,但是在實際的開發過程中沒有什么意義,我們會發現改方法會產生阻塞,但是卻不能用來刷新UI,也沒有體現多核處理器的優勢。

 

  1. //后臺同步執行  -(void)action4{            dispatch_sync(dispatch_get_global_queue(0, 0), ^{                    for (int i = 0; i< 10000; i++) NSLog(@"=================%d",i);                });            NSLog(@"=================后臺同步執行");  }  

     

我們也是連續點擊兩次按鈕,執行兩次action4方法,我們看到的打印結果讓我們很驚訝,可能會有人說,dispatch_get_global_queue隊列不是并發隊列嗎,怎么執行的結果是這樣的。在這里我需要解釋下,由于提交給全局隊列的執行方式是同步的,這里實際上是產生了阻塞,即必須是該任務完成后才能執行下面的任務,我們看到打印語句2執行的位置就知道了。所以同步一般在刷新UI界面或者處理共享數據的時候使用,而且任務的處理時間不能太長,會影響用戶體驗。

 

 

2013-12-09 16:04:35.967 TestGCD[1385:a0b] =================0

2013-12-09 16:04:35.969 TestGCD[1385:a0b] =================1

2013-12-09 16:04:35.969 TestGCD[1385:a0b] =================2

......

2013-12-09 16:04:40.645 TestGCD[1385:a0b] =================9997

2013-12-09 16:04:40.645 TestGCD[1385:a0b] =================9998

2013-12-09 16:04:40.646 TestGCD[1385:a0b] =================9999

2013-12-09 16:04:40.646 TestGCD[1385:a0b] =================后臺同步執行

2013-12-09 16:04:40.647 TestGCD[1385:a0b] =================0

2013-12-09 16:04:40.647 TestGCD[1385:a0b] =================1

2013-12-09 16:04:40.648 TestGCD[1385:a0b] =================2

2013-12-09 16:04:40.648 TestGCD[1385:a0b] =================3

......

 

2013-12-09 16:04:45.218 TestGCD[1385:a0b] =================9998

2013-12-09 16:04:45.218 TestGCD[1385:a0b] =================9999

2013-12-09 16:04:45.218 TestGCD[1385:a0b] =================后臺同步執行

 

 

 

例子五,開發人員可以自己定義一個隊列用于執行后臺線程,同全局隊列使用方法基本類似,在非arc的情況下,需要開發人員手動釋放。

 

 
  1. //自定義dispatch_queue_t  -(void)action5{            dispatch_queue_t urls_queue = dispatch_queue_create("myQueue", NULL);            dispatch_async(urls_queue, ^{                    for (int i = 0; i< 5; i++) NSLog(@"自定義dispatch_queue_t===========%d",i);                    dispatch_sync(dispatch_get_main_queue(), ^{                           NSLog(@"同主線程交互===========");          });        });            dispatch_release(urls_queue);   //arc不要  }  

     

打印結果:

 

 

2013-12-09 16:43:52.416 TestGCD[1464:1417] 自定義dispatch_queue_t===========0

2013-12-09 16:43:52.417 TestGCD[1464:1417] 自定義dispatch_queue_t===========1

2013-12-09 16:43:52.418 TestGCD[1464:1417] 自定義dispatch_queue_t===========2

2013-12-09 16:43:52.419 TestGCD[1464:1417] 自定義dispatch_queue_t===========3

2013-12-09 16:43:52.420 TestGCD[1464:1417] 自定義dispatch_queue_t===========4

2013-12-09 16:43:52.420 TestGCD[1464:a0b] 同主線程交互===========

 

 

例子六,除此之外,調度方式還有延遲執行。

 

 

  1. //延遲3秒執行  -(void)action6{            double delayInSeconds = 3.0;      dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));      dispatch_after(popTime, dispatch_get_main_queue(), ^(void){                    NSLog(@"延遲3秒執行===========");        });  }  

     

打印結果:

 

 

2013-12-09 16:48:58.473 TestGCD[1484:a0b] 延遲3秒執行===========

 
 

例子七,一次性執行,主要用于創建單例對象。在ios4.0以前,我們創建單例會用到互斥鎖@synchronized來確保其他線程沒有對self對象進行修改,一般在共用變量的時候使用。

 
  1. + (NetworkManager *)getNetworkInstance{         @synchronized(self){                    if (nil == network) network = [[NetworkManager alloc] init];      }          return network;  }  

     

ios4.0之后,我們可以用GCD創建單例,下面的GCD語法只會執行一次,代碼如下:

 

 
  1. +(UserManager *)sharedManager{            static UserManager *_manager = nil;            static dispatch_once_t onceToken;            dispatch_once(&onceToken, ^{                    _manager = [[UserManager alloc]init];        });            return _manager;  }  

     

該方法的好處有:一、線程安全;二、很好滿足靜態分析器的要求;三、兼容ARC;四、僅需要少量代碼。

 

 

 

例子八,合并匯總結果,dispatch_group_t隊列非常好用,當我們有多個異步執行的隊列在執行,我們還有一個任務需要用到這多個異步執行隊列執行的結果時,我們就會用到dispatch_group_t,廢話不多說,直接上代碼:

 

 

 
  1. //合并匯總結果  -(void)action8{         dispatch_group_t group = dispatch_group_create();            dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{                    for (int i = 0; i < 5; i++) NSLog(@"并行執行的線程一=============%d",i);      });            dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{                    for (int i = 0; i < 5; i++) NSLog(@"并行執行的線程二=============%d",i);        });            dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{                   NSLog(@"匯總結果===========");        });            dispatch_release(group);  }  

     

 

打印結果:
 

2013-12-10 11:48:39.139 TestGCD[699:1403] 并行執行的線程一=============0

2013-12-10 11:48:39.139 TestGCD[699:3807] 并行執行的線程二=============0

2013-12-10 11:48:39.143 TestGCD[699:1403] 并行執行的線程一=============1

2013-12-10 11:48:39.143 TestGCD[699:3807] 并行執行的線程二=============1

2013-12-10 11:48:39.144 TestGCD[699:1403] 并行執行的線程一=============2

2013-12-10 11:48:39.144 TestGCD[699:3807] 并行執行的線程二=============2

2013-12-10 11:48:39.145 TestGCD[699:1403] 并行執行的線程一=============3

2013-12-10 11:48:39.145 TestGCD[699:3807] 并行執行的線程二=============3

2013-12-10 11:48:39.146 TestGCD[699:3807] 并行執行的線程二=============4

2013-12-10 11:48:39.146 TestGCD[699:1403] 并行執行的線程一=============4

2013-12-10 11:48:39.147 TestGCD[699:3807] 匯總結果===========

 

我們看到第三條打印語句是在前兩條打印語句執行之后才執行。

 

這也是我綜合了官方文檔和網上的很多資料總結出來的,并且用實際的代碼調試出來的結果,希望能給大家一些幫助,對于其中的不足,歡迎大家給出不同意見。

 

 

參考:http://www.49028c.com/pure/archive/2013/03/31/2977420.html

 

 

 

 

2014_07_16今天再次翻看GCD。再瀏覽過程中,發現了另外一篇不錯的講解隊列的帖子,現轉發之,希望能對你有所幫助和啟發,里面提到死鎖的問題,可以思考和交流。

原文地址:http://www.49028c.com/sunfrog/p/3305614.html

GCD編程的核心就是dispatch隊列,dispatch block的執行最終都會放進某個隊列中去進行,它類似NSOperationQueue但更復雜也更強大,并且可以嵌套使用。所以說,結合block實現的GCD,把函數閉包(Closure)的特性發揮得淋漓盡致。

 

dispatch隊列的生成可以有這幾種方式:

1. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial"DISPATCH_QUEUE_SERIAL); //生成一個串行隊列,隊列中的block按照先進先出(FIFO)的順序去執行,實際上為單線程執行。第一個參數是隊列的名稱,在調試程序時會非常有用,所有盡量不要重名了。

2. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent"DISPATCH_QUEUE_CONCURRENT); //生成一個并發執行隊列,block被分發到多個線程去執行

3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //獲得程序進程缺省產生的并發隊列,可設定優先級來選擇高、中、低三個優先級隊列。由于是系統默認生成的,所以無法調用dispatch_resume()和dispatch_suspend()來控制執行繼續或中斷。需要注意的是,三個隊列不代表三個線程,可能會有更多的線程。并發隊列可以根據實際情況來自動產生合理的線程數,也可理解為dispatch隊列實現了一個線程池的管理,對于程序邏輯是透明的。

官網文檔解釋說共有三個并發隊列,但實際還有一個更低優先級的隊列,設置優先級為DISPATCH_QUEUE_PRIORITY_BACKGROUND。Xcode調試時可以觀察到正在使用的各個dispatch隊列。

4. dispatch_queue_t queue = dispatch_get_main_queue(); //獲得主線程的dispatch隊列,實際是一個串行隊列。同樣無法控制主線程dispatch隊列的執行繼續或中斷。

接下來我們可以使用dispatch_async或dispatch_sync函數來加載需要運行的block。

dispatch_async(queue, ^{

  //block具體代碼

}); //異步執行block,函數立即返回

dispatch_sync(queue, ^{

  //block具體代碼

}); //同步執行block,函數不返回,一直等到block執行完畢。編譯器會根據實際情況優化代碼,所以有時候你會發現block其實還在當前線程上執行,并沒用產生新線程。

實際編程經驗告訴我們,盡可能避免使用dispatch_sync,嵌套使用時還容易引起程序死鎖。

如果queue1是一個串行隊列的話,這段代碼立即產生死鎖:

   dispatch_sync(queue1, ^{

      dispatch_sync(queue1, ^{

    ......

  });

  ......

 });

不妨思考下,為什么下面代碼在主線程中執行會死鎖:

dispatch_sync(dispatch_get_main_queue(), ^{

  ......

}); 

 

那實際運用中,一般可以用dispatch這樣來寫,常見的網絡請求數據多線程執行模型:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

  //子線程中開始網絡請求數據

  //更新數據模型

  dispatch_sync(dispatch_get_main_queue(), ^{

    //在主線程中更新UI代碼

  });

});

程序的后臺運行和UI更新代碼緊湊,代碼邏輯一目了然。

 

dispatch隊列是線程安全的,可以利用串行隊列實現鎖的功能。比如多線程寫同一數據庫,需要保持寫入的順序和每次寫入的完整性,簡單地利用串行隊列即可實現:

dispatch_queue_t queue1 = dispatch_queue_create("com.dispatch.writedb"DISPATCH_QUEUE_SERIAL);

- (void)writeDB:(NSData *)data

{

  dispatch_async(queue1, ^{

    //write database

  });

} 

下一次調用writeDB:必須等到上次調用完成后才能進行,保證writeDB:方法是線程安全的。 

 

dispatch隊列還實現其它一些常用函數,包括:

void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t)); //重復執行block,需要注意的是這個方法是同步返回,也就是說等到所有block執行完畢才返回,如需異步返回則嵌套在dispatch_async中來使用。多個block的運行是否并發或串行執行也依賴queue的是否并發或串行。

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); //這個函數可以設置同步執行的block,它會等到在它加入隊列之前的block執行完畢后,才開始執行。在它之后加入隊列的block,則等到這個block執行完畢后才開始執行。

void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block); //同上,除了它是同步返回函數

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); //延遲執行block

最后再來看看dispatch隊列的一個很有特色的函數:

void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue);

它會把需要執行的任務對象指定到不同的隊列中去處理,這個任務對象可以是dispatch隊列,也可以是dispatch源(以后博文會介紹)。而且這個過程可以是動態的,可以實現隊列的動態調度管理等等。比如說有兩個隊列dispatchA和dispatchB,這時把dispatchA指派到dispatchB:

dispatch_set_target_queue(dispatchA, dispatchB);

那么dispatchA上還未運行的block會在dispatchB上運行。這時如果暫停dispatchA運行:

dispatch_suspend(dispatchA);

則只會暫停dispatchA上原來的block的執行,dispatchB的block則不受影響。而如果暫停dispatchB的運行,則會暫停dispatchA的運行。

這里只簡單舉個例子,說明dispatch隊列運行的靈活性,在實際應用中你會逐步發掘出它的潛力。

dispatch隊列不支持cancel(取消),沒有實現dispatch_cancel()函數,不像NSOperationQueue,不得不說這是個小小的缺憾。 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩美女视频在线观看| 国内精品久久久久影院 日本资源| 久久久久久高潮国产精品视| 中文字幕亚洲综合久久筱田步美| 亚洲精品大尺度| 欧美视频不卡中文| 中文字幕一区电影| 国内精品久久久久久久| 国产女人精品视频| 亚洲国产精品女人久久久| 亚洲一区二区免费| 亚洲午夜小视频| 亚洲国产精品va在线| 国产成人亚洲综合青青| 欧美午夜丰满在线18影院| 成人久久一区二区| 国产精品久久久久久久久久东京| 97婷婷涩涩精品一区| 91国内在线视频| 亚洲一二三在线| 亚洲丝袜一区在线| 精品一区二区三区三区| 亚洲国产欧美一区二区丝袜黑人| 久久国产精品电影| 精品一区精品二区| 久久精品视频在线| 亚洲自拍偷拍色片视频| 91美女片黄在线观看游戏| 国产成人精品免高潮在线观看| 性欧美视频videos6一9| 97热精品视频官网| 国产精品自产拍高潮在线观看| 欧美日韩性生活视频| 日韩有码在线观看| 最近2019年中文视频免费在线观看| 5566成人精品视频免费| 91免费在线视频网站| 日韩精品高清在线观看| 久久久久久免费精品| 国产不卡av在线免费观看| 国产精品视频自拍| 欧美日韩性视频| 中文字幕在线日韩| 欧美激情视频播放| 91干在线观看| 亚洲视频第一页| 国语自产偷拍精品视频偷| 亚洲人成在线免费观看| 91麻豆国产精品| 奇米4444一区二区三区| 日韩精品视频中文在线观看| 国产精品久久久久久婷婷天堂| 欧美极品第一页| 国产色视频一区| 国产精品va在线播放| 尤物九九久久国产精品的分类| 亚洲人精选亚洲人成在线| 日韩精品免费视频| 日韩在线观看你懂的| 亚洲免费视频网站| 国产欧美一区二区| 国产精品激情av电影在线观看| 亚洲tv在线观看| 久久全国免费视频| 免费91麻豆精品国产自产在线观看| 欧美中文字幕视频| www.国产精品一二区| 日韩视频第一页| 亚洲2020天天堂在线观看| 亚洲精品中文字| 国产精品久久久久久久久久ktv| 一区二区三区美女xx视频| 日本亚洲欧洲色| 国产精品久久在线观看| 国产精品视频自拍| 亚洲а∨天堂久久精品9966| 日韩在线观看你懂的| 欧美性在线视频| 一本色道久久综合狠狠躁篇怎么玩| 日韩人在线观看| 欧美中文在线视频| 91九色在线视频| 啊v视频在线一区二区三区| 欧美精品久久一区二区| 久久久亚洲国产| 日韩免费在线免费观看| 深夜精品寂寞黄网站在线观看| 欧美疯狂做受xxxx高潮| 97视频在线免费观看| 久久伊人精品一区二区三区| 国产精品永久免费在线| 精品国产一区二区三区在线观看| 色香阁99久久精品久久久| 欧美成年人视频网站欧美| 亚洲永久免费观看| 97婷婷涩涩精品一区| 国产精品网站大全| 国产午夜精品一区二区三区| 97香蕉久久夜色精品国产| 亚洲人a成www在线影院| 欧美激情亚洲国产| 欧美日韩xxx| 91网站在线免费观看| 8x拔播拔播x8国产精品| 色伦专区97中文字幕| 欧美成人精品不卡视频在线观看| 视频直播国产精品| 日本久久中文字幕| 欧美日韩中文在线| 亚洲女成人图区| 国产精品夫妻激情| 欧美激情videos| 欧美激情乱人伦| 高清亚洲成在人网站天堂| 92看片淫黄大片欧美看国产片| 黑人精品xxx一区一二区| 国产男女猛烈无遮挡91| 亚洲成人激情在线| 555www成人网| 国产精品永久免费视频| 日韩成人中文字幕在线观看| 欧美日韩国产成人在线观看| 日韩电影中文字幕在线观看| 麻豆成人在线看| 亚洲自拍另类欧美丝袜| 国产精品99一区| 欧美精品videos性欧美| 日韩av观看网址| 欧美成人激情在线| 丁香五六月婷婷久久激情| 综合欧美国产视频二区| 国内精品在线一区| 亚洲欧美制服第一页| 欧美日韩中文字幕在线| 欧美色道久久88综合亚洲精品| 91影院在线免费观看视频| 91久久精品国产91性色| 国产一区二区激情| 国产日韩欧美在线视频观看| 亚洲欧洲日产国产网站| 国产九九精品视频| 国产精品免费看久久久香蕉| 日韩高清电影好看的电视剧电影| 色婷婷av一区二区三区在线观看| 69av在线视频| 中文字幕日韩在线播放| 国产精品女主播视频| 国产精品久久久久国产a级| 日韩美女视频免费看| 尤物tv国产一区| 欧美性高潮床叫视频| 国产色婷婷国产综合在线理论片a| 97色在线视频| 国产精品一区二区三区久久| 精品国偷自产在线视频| 国产精品羞羞答答| 久久久精品国产亚洲| 精品亚洲精品福利线在观看| 97色伦亚洲国产| 久久精品国产亚洲精品| 2021国产精品视频| 欧美精品在线观看| 国产美女精彩久久| 亚洲高清久久网|