【iOS】玩轉(zhuǎn)-GCD

本文來(lái)自尚妝iOS團(tuán)隊(duì)嘉文
發(fā)表于尚妝github博客操禀,歡迎訂閱厂庇!

GCD介紹


Grand Central Dispatch (GCD)是Apple開(kāi)發(fā)的一個(gè)多核編程的解決方法
基于C語(yǔ)言觉啊,提供了非常多強(qiáng)大的函數(shù)

術(shù)語(yǔ)


同步 (Synchronous)

在當(dāng)前線程中執(zhí)行任務(wù)嘉抒,不具備開(kāi)啟新線程的能力
提交的任務(wù)在執(zhí)行完成后才會(huì)返回
同步函數(shù): dispatch_sync()

異步 (Asynchronous)

在新線程中執(zhí)行任務(wù)姿鸿,具備開(kāi)啟新線程的能力
提交的任務(wù)立刻返回殖卑,在后臺(tái)隊(duì)列中執(zhí)行
異步函數(shù): dispatch_async()

串行 (Serial)

一個(gè)任務(wù)執(zhí)行完畢后站削,再執(zhí)行下一個(gè)任務(wù)

并發(fā) (Concurrent)

多個(gè)任務(wù)同時(shí)執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程),只有在異步函數(shù)下才有效

描述 說(shuō)明
queue 隊(duì)列
main 主隊(duì)列
global 全局隊(duì)列
dispatch_queue_t 描述隊(duì)列
dispatch_block_t 描述任務(wù)
dispatch_once_t 描述一次性
dispatch_time_t 描述時(shí)間
dispatch_group_t 描述隊(duì)列組
dispatch_semaphore_t 描述信號(hào)量
函數(shù) 說(shuō)明
dispatch_sync() 同步執(zhí)行
dispatch_async() 異步執(zhí)行
dispatch_after() 延時(shí)執(zhí)行
dispatch_once() 一次性執(zhí)行
dispatch_apply() 提交隊(duì)列
dispatch_queue_create() 創(chuàng)建隊(duì)列
dispatch_group_create() 創(chuàng)建隊(duì)列組
dispatch_group_async() 提交任務(wù)到隊(duì)列組
dispatch_group_enter() / dispatch_group_leave() 將隊(duì)列組中的任務(wù)未執(zhí)行完畢的任務(wù)數(shù)目加減1(兩個(gè)函數(shù)要配合使用)
dispatch_group_notify() 監(jiān)聽(tīng)隊(duì)列組執(zhí)行完畢
dispatch_group_wait() 設(shè)置等待時(shí)間(返回 0成功,1失敗)
注意:

1.所有的執(zhí)行都放到隊(duì)列中(queue),隊(duì)列的特點(diǎn)是FIFO(先提交的先執(zhí)行)
2.必須在主線程訪問(wèn) UIKit 的類(lèi)
3.并發(fā)隊(duì)列只在異步函數(shù)下才有效

基本使用


 NSLog(@"當(dāng)前線程: %@", [NSThread currentThread]);
 //獲取主隊(duì)列
 dispatch_queue_t mainQueue = dispatch_get_main_queue();
 
 //獲取全局并發(fā)隊(duì)列
 dispatch_queue_t otherQueue =   dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
 //同步函數(shù)(在當(dāng)前線程中執(zhí)行,不具備開(kāi)啟新線程的能力)
 dispatch_sync(otherQueue, ^{
      NSLog(@"同步 %@", [NSThread currentThread]);
 });
    
 //異步函數(shù)(在另一條線程中執(zhí)行,具備開(kāi)啟新線程的能力)
 dispatch_async(otherQueue, ^{
      NSLog(@"異步 %@", [NSThread currentThread]);
 });
    
 //輸出:   當(dāng)前線程: <NSThread: 0x7f81bac06670>{number = 1, name = main}
 //輸出:   同步 <NSThread: 0x7f81bac06670>{number = 1, name = main}
 //輸出:   異步 <NSThread: 0x7f81bae35be0>{number = 3, name = (null)}
延時(shí)執(zhí)行 dispatch_after()

dispatch_after()延遲一段時(shí)間把一項(xiàng)任務(wù)提交到隊(duì)列中執(zhí)行孵稽,返回之后就不能取消
常用來(lái)在在主隊(duì)列上延遲執(zhí)行一項(xiàng)任務(wù)

    NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);

    //GCD延時(shí)調(diào)用(主線程)(主隊(duì)列)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"GCD延時(shí)(主線程) %@", [NSThread currentThread]);
    });
    
    //GCD延時(shí)調(diào)用(其他線程)(全局并發(fā)隊(duì)列)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"GCD延時(shí)(其他線程) %@", [NSThread currentThread]);
    });

    //輸出:   當(dāng)前線程 <NSThread: 0x7f8cb9701990>{number = 1, name = main}
    //輸出:   GCD延時(shí)(主線程) <NSThread: 0x7f8cb9701990>{number = 1, name = main}
    //輸出:   GCD延時(shí)(其他線程) <NSThread: 0x7f8cb9513ee0>{number = 3, name = (null)}
一次性執(zhí)行 dispatch_once()

整個(gè)程序運(yùn)行中,只會(huì)執(zhí)行一次 (默認(rèn)線程是安全的)
dispatch_once() 以線程安全的方式執(zhí)行且僅執(zhí)行其代碼塊一次

    for (NSInteger i = 0; i < 10; i++) {
      
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"GCD一次性執(zhí)行(默認(rèn)線程是安全的)");
        });
        
    }

 //輸出:   GCD一次性執(zhí)行(默認(rèn)線程是安全的)
//使用GCD初始化單例
+ (instancetype)sharedManager { 
  
    static PhotoManager *sharedPhotoManager = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
        sharedPhotoManager = [[PhotoManager alloc] init]; 
    }); 

    return sharedPhotoManager; 
} 
提交 dispatch_apply()

把一項(xiàng)任務(wù)提交到隊(duì)列中多次執(zhí)行许起,具體是并行執(zhí)行還是串行執(zhí)行由隊(duì)列本身決定
dispatch_apply不會(huì)立刻返回十偶,在執(zhí)行完畢后才會(huì)返回,是同步的調(diào)用园细。

隊(duì)列

任務(wù)1,任務(wù)2依次執(zhí)行,所有任務(wù)都執(zhí)行成功后回到主線程
(效率不高)

 NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
   
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //全局并發(fā)隊(duì)列
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
        }
        
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
        }
        
        dispatch_async(dispatch_get_main_queue(), ^{
            //主隊(duì)列
            NSLog(@"主線程執(zhí)行(刷新UI) %@", [NSThread currentThread]);
        });
        
    });
    
    //輸出:   當(dāng)前線程 <NSThread: 0x7fa78040b8b0>{number = 1, name = main}
    //輸出:   任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)}
    //輸出:   主線程(刷新UI) <NSThread: 0x7f9da1705940>{number = 1, name = main}
隊(duì)列組

任務(wù)1,任務(wù)2同時(shí)執(zhí)行,所有任務(wù)都執(zhí)行成功后回到主線程
(效率高)

    NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
    
    //(1)創(chuàng)建一個(gè)隊(duì)列組
    dispatch_group_t group= dispatch_group_create();
    
    //(2)開(kāi)啟任務(wù)1
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
        }
        
    });
    
    //(3)開(kāi)啟任務(wù)2
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
        }
        
    });
    
    //(4)所有任務(wù)執(zhí)行完畢,回到主線程
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        
        NSLog(@"主線程(刷新UI) %@", [NSThread currentThread]);
        
    });
    
    //輸出:   當(dāng)前線程 <NSThread: 0x7fd951704e70>{number = 1, name = main}
    //輸出:   任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
    //輸出:   任務(wù)1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)}
    //輸出:   主線程(刷新UI) <NSThread: 0x7ff65a406fb0>{number = 1, name = main}

串行與并發(fā)


各個(gè)隊(duì)列的執(zhí)行效果
串行隊(duì)列
串行隊(duì)列

一個(gè)任務(wù)執(zhí)行完畢后惦积,再執(zhí)行下一個(gè)任務(wù)
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列,放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行

    //(1)使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
    //參數(shù)1: 隊(duì)列名稱(chēng)
 //參數(shù)2: 隊(duì)列屬性 (一般用NULL)
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
    
    //(2)使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
    dispatch_queue_t serialMainQueue = dispatch_get_main_queue();
并發(fā)隊(duì)列
并發(fā)隊(duì)列

多個(gè)任務(wù)并發(fā)執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù))

<u>并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效!!!</u>

GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用猛频,不需要手動(dòng)創(chuàng)建

并發(fā)隊(duì)列優(yōu)先級(jí) 快捷值 優(yōu)先級(jí)
DISPATCH_QUEUE_PRIORITY_HIGH 2
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 中(默認(rèn))
DISPATCH_QUEUE_PRIORITY_LOW (-2)
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后臺(tái)
 //(1)使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
    //參數(shù)1: 優(yōu)先級(jí)
 //參數(shù)2: 暫時(shí)無(wú)用參數(shù) (傳0)
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
異步函數(shù)_并發(fā)隊(duì)列

(開(kāi)啟新線程,并發(fā)執(zhí)行任務(wù))

    NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
    });
    
    //輸出:   當(dāng)前線程 <NSThread: 0x7fbe83c067c0>{number = 1, name = main}
    //輸出:   任務(wù)1 <NSThread: 0x7fb84160ed90>{number = 3, name = (null)}
    //輸出:   任務(wù)3 <NSThread: 0x7fb841752940>{number = 4, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7fb8414167b0>{number = 5, name = (null)}
異步函數(shù)_串行隊(duì)列

(開(kāi)啟新線程,串行執(zhí)行任務(wù))

    NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
    //創(chuàng)建串行隊(duì)列
    dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
    
    dispatch_async(serialQueue, ^{
        NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
    });
    
    dispatch_async(serialQueue, ^{
        NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
    });
    
    dispatch_async(serialQueue, ^{
        NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
    });
    
    //輸出:   當(dāng)前線程 <NSThread: 0x7fc192e05380>{number = 1, name = main}
    //輸出:   任務(wù)1 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
    //輸出:   任務(wù)2 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
    //輸出:   任務(wù)3 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
同步函數(shù)_并發(fā)隊(duì)列

(不會(huì)開(kāi)啟新線程,并發(fā)執(zhí)行任務(wù)失效!)

    NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
    });
    
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
    });
    
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
    });
    
    //輸出:   當(dāng)前線程 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
    //輸出:   任務(wù)1 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
    //輸出:   任務(wù)2 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
    //輸出:   任務(wù)3 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
同步函數(shù)_串行隊(duì)列

(不會(huì)開(kāi)啟新線程,串行執(zhí)行任務(wù))

 NSLog(@"當(dāng)前線程 %@", [NSThread currentThread]);
 //創(chuàng)建串行隊(duì)列
 dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL);
 dispatch_sync(serialQueue, ^{
     NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
 });

 dispatch_sync(serialQueue, ^{
      NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
 });

 dispatch_sync(serialQueue, ^{
     NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
 });

 //輸出:   當(dāng)前線程 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
 //輸出:   任務(wù)1 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
 //輸出:   任務(wù)2 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
 //輸出:   任務(wù)3 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狮崩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伦乔,更是在濱河造成了極大的恐慌厉亏,老刑警劉巖董习,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烈和,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡皿淋,警方通過(guò)查閱死者的電腦和手機(jī)招刹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)窝趣,“玉大人疯暑,你說(shuō)我怎么就攤上這事⊙剖妫” “怎么了妇拯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)洗鸵。 經(jīng)常有香客問(wèn)我越锈,道長(zhǎng),這世上最難降的妖魔是什么膘滨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任甘凭,我火速辦了婚禮,結(jié)果婚禮上火邓,老公的妹妹穿的比我還像新娘丹弱。我一直安慰自己,他們只是感情好铲咨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布躲胳。 她就那樣靜靜地躺著,像睡著了一般纤勒。 火紅的嫁衣襯著肌膚如雪坯苹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天踊东,我揣著相機(jī)與錄音北滥,去河邊找鬼刚操。 笑死,一個(gè)胖子當(dāng)著我的面吹牛再芋,可吹牛的內(nèi)容都是我干的菊霜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼济赎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鉴逞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起司训,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤构捡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后壳猜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體勾徽,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年统扳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喘帚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咒钟,死狀恐怖吹由,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情朱嘴,我是刑警寧澤倾鲫,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站萍嬉,受9級(jí)特大地震影響乌昔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帚湘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一玫荣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧大诸,春花似錦捅厂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至贿堰,卻和暖如春辙芍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工故硅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庶灿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓吃衅,卻偏偏與公主長(zhǎng)得像往踢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子徘层,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容