GCD常見用法和實(shí)踐中需要注意的點(diǎn)

常見問題總結(jié):
1: GCD里面有多少種全局隊(duì)列?
詳情請查看dispatch queue.h 頭文件


88AA8E08-1574-49C4-B87F-0E1B0A0A05B7.png
26AEE975-887C-4A41-BC40-D0B9A16B834D.png
  Global Dispatch Queue有如下8種
     Global Dispatch Queue (High priority)
     Global Dispatch Queue (Default priority)
     Global Dispatch Queue (Low priority)
     Global Dispatch Queue (Background priority)
     Global Dispatch Queue (High overcommit priority)
     Global Dispatch Queue (Default overcommit priority)
     Global Dispatch Queue (Low overcommit priority)
     Global Dispatch Queue (Background overcommit priority)
 
   注意前面四種 和后面四種不同優(yōu)先級的Queue有一詞之差:Overcommit朽褪。其區(qū)別就在于Overcommit Queue不管系統(tǒng)狀態(tài)如何都會強(qiáng)制生成線程隊(duì)列置吓。

2: 基本概念闡述

 1:GCD 是什么鳍贾?
 GCD全稱Grand Central Dispatch
 GCD 在后端管理著一個(gè)線程池。GCD 不僅決定著你的代碼塊將在哪個(gè)線程被執(zhí)行交洗,它還根據(jù)可用的系統(tǒng)資源對這些線程進(jìn)行管理骑科。這樣可以將開發(fā)者從線程管理的工作中解放出來,通過集中的管理線程构拳,來緩解大量線程被創(chuàng)建的問題咆爽。
 GCD 帶來的另一個(gè)重要改變是,作為開發(fā)者可以將工作考慮為一個(gè)隊(duì)列置森,而不是一堆線程斗埂,這種并行的抽象模型更容易掌握和使用。當(dāng)多個(gè)隊(duì)列要處理塊時(shí)凫海,系統(tǒng)可以自由分配額外的線程來同時(shí)調(diào)用塊呛凶。當(dāng)隊(duì)列變空時(shí),這些線程會自動釋放.
 
 首先行贪,系統(tǒng)提供給你一個(gè)叫做 主隊(duì)列(main queue) 的特殊隊(duì)列漾稀。和其它串行隊(duì)列一樣,這個(gè)隊(duì)列中的任務(wù)一次只能執(zhí)行一個(gè)建瘫。然而崭捍,它能保證所有的任務(wù)都在主線程執(zhí)行,而主線程是唯一可用于更新 UI 的線程啰脚。這個(gè)隊(duì)列就是用于發(fā)生消息給 UIView 或發(fā)送通知的殷蛇。
 
 系統(tǒng)同時(shí)提供給你好幾個(gè)并發(fā)隊(duì)列。它們叫做 全局調(diào)度隊(duì)列(Global Dispatch Queues) 橄浓。目前的四個(gè)全局隊(duì)列有著不同的優(yōu)先級:background粒梦、low、default 以及 high荸实。要知道匀们,Apple 的 API 也會使用這些隊(duì)列,所以你添加的任何任務(wù)都不會是這些隊(duì)列中唯一的任務(wù)泪勒。
 
 最后昼蛀,你也可以創(chuàng)建自己的串行隊(duì)列或并發(fā)隊(duì)列。
    主隊(duì)列圆存、
    串行隊(duì)列叼旋、
    并發(fā)隊(duì)列。
 
 2.GCD相比其他多線程有哪些優(yōu)點(diǎn)沦辙?
 
 GCD 能通過推遲昂貴計(jì)算任務(wù)并在后臺運(yùn)行它們來改善你的應(yīng)用的響應(yīng)性能夫植。
 GCD 提供一個(gè)易于使用的并發(fā)模型而不僅僅只是鎖和線程,以幫助我們避開并發(fā)陷阱。
 GCD 具有在常見模式(例如單例)上用更高性能的原語優(yōu)化你的代碼的潛在能力详民。
 GCD 會自動利用更多的CPU內(nèi)核(比如雙核延欠、四核)
 3.GCD術(shù)語
 
 串行(Serial):讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))
 并發(fā)(Concurrent):可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效沈跨。
 同步(Synchronous):在當(dāng)前線程中執(zhí)行任務(wù)由捎,不具備開啟新線程的能力
 異步(Asynchronous):在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
#pragma mark - 串行隊(duì)列
- (void)dispatch_serialQueue{
    //串行隊(duì)列
    dispatch_queue_t serialQueue;
    serialQueue = dispatch_queue_create("com.example.SerialQueue", DISPATCH_QUEUE_SERIAL);// dispatch_queue_attr_t設(shè)置成NULL的時(shí)候默認(rèn)代表串行饿凛。
    dispatch_async(serialQueue, ^{
         // something
         NSLog(@"current thread = com.example.SerialQueue  %@", [NSThread currentThread]);
    });
}
#pragma mark - 并發(fā)隊(duì)列
- (void)dispatch_concurrentQueue{
    //并發(fā)隊(duì)列
    dispatch_queue_t concurrentQueue;
    concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // something
        NSLog(@"current thread = com.example.ConcurrentQueue %@", [NSThread currentThread]);
    });
}
#pragma mark - 主隊(duì)列
- (void)dispath_mainQueue{
    // 主隊(duì)列:
    dispatch_queue_t mainQueue;
    mainQueue = dispatch_get_main_queue();
    
    dispatch_async(dispatch_get_main_queue(), ^{
        // something
        NSLog(@"current thread = %@  main ", [NSThread currentThread]);
        
    });
}
#pragma mark - 自定義dispatch_queue_t
- (void)dispatch_queue_t{
    // 自定義dispatch_queue_t
    dispatch_queue_t emailQueue = dispatch_queue_create("www.summerHearts@163.com", NULL);
    dispatch_async(emailQueue, ^{
        NSLog(@"current thread = %@", [NSThread currentThread]);
    });
}

#pragma mark -信號量
- (void)dispatch_semaphore{
    //信號量:
    /*
     dispatch Semaphore 是持有計(jì)數(shù)的信號狞玛,該計(jì)數(shù)是多線程編程中的計(jì)數(shù)類型信號。所謂信號涧窒,就是過馬路時(shí)常用的手旗心肪。可以通過時(shí)舉起手旗纠吴,不可通過時(shí)放下手旗硬鞍。使用計(jì)數(shù)來實(shí)現(xiàn)該功能。計(jì)數(shù)為0時(shí)等待戴已,計(jì)數(shù)為1或者大于1固该,減去1而不等待。
     */
    
    dispatch_queue_t queues = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    NSMutableArray *array = [NSMutableArray array];
    
    for (int i = 0; i <  10; ++i) {
        dispatch_async(queues, ^{
            /*
             * 等待 Dispatch Semaphore.
             * 一直等待恭陡,直到Dispatch Semaphore的計(jì)數(shù)達(dá)到大于等于1
             *  // 由于是異步執(zhí)行的蹬音,所以每次循環(huán)Block里面的dispatch_semaphore_signal根本還沒有執(zhí)行就會執(zhí)行dispatch_semaphore_wait上煤,從而semaphore-1.當(dāng)循環(huán)10此后休玩,semaphore等于0,則會阻塞線程劫狠,直到執(zhí)行了Block的dispatch_semaphore_signal 才會繼續(xù)執(zhí)行
             */
            
            long result =  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@">>>>   %ld",result);
            
            /*
                此時(shí) result為0拴疤, 可安全的執(zhí)行需要進(jìn)行排他控制的處理。該處理結(jié)束的時(shí)候通過dispatch_semaphore_signal函數(shù)將dispatch_semaphore的計(jì)數(shù)值加1.
             */
            /*
             由于Dispatch semaphore 的計(jì)數(shù)值達(dá)到大于或者等于等一1,所以將 Dispatch semaphore的計(jì)數(shù)值減去1. dispatch_semaphore_wait函數(shù)執(zhí)行返回独泞。即執(zhí)行到此呐矾,Dispatch semaphore 的計(jì)數(shù)值為0.
             
             */
            [array addObject:[NSNumber numberWithInt:i]];
            
            /*
             dispatch_semaphore_signal函數(shù)將dispatch semaphore 的計(jì)數(shù)值加1.如果有通過 dispatch_semaphore_wait函數(shù)等待 dispatch semaphore的計(jì)數(shù)值增加的線程就由最先等待的線程執(zhí)行驹饺。
             */
            dispatch_semaphore_signal(semaphore);
        });
            //dispatch_semaphore_wait 函數(shù)等待Dispatch Semaphore的計(jì)數(shù)值達(dá)到大于或者等于1.當(dāng)計(jì)數(shù)值大于等于1宵统,或者在待機(jī)中技術(shù)值大于或者等于1,對該計(jì)數(shù)進(jìn)行減法并從dispatch_semaphore_wait函數(shù)返回硫戈。
    }
}

#pragma mark - 柵欄
- (void)dispatch_barrier_async{
    // 自定義并發(fā)隊(duì)列
    /*
     通過dispatch_barrier_async函數(shù)提交的任務(wù)會等它前面的任務(wù)執(zhí)行完才開始荞膘,然后它后面的任務(wù)必須等它執(zhí)行完畢才能開始.
     必須使用dispatch_queue_create創(chuàng)建的隊(duì)列才會達(dá)到上面的效果.dispatch_barrier_async 起到了“承上啟下”的作用罚随。它保證此前的任務(wù)都先于自己執(zhí)行,此后的任務(wù)也遲于自己執(zhí)行羽资。正如barrier的含義一樣淘菩,它起到了一個(gè)柵欄、或是分水嶺的作用屠升。
     這樣一來潮改,使用并行隊(duì)列和 dispatc_barrier_async 方法狭郑,就可以高效的進(jìn)行數(shù)據(jù)和文件讀寫了。
    */

    /*
     dispatch_barrier_async函數(shù)會等待追加到concurrent dispatch queue 上的并行執(zhí)行的處理全部結(jié)束之后汇在,再將制訂的處理追加到該concurrent dispatch queue中翰萨。然后再由dispatch_barrier_async函數(shù)追加的處理執(zhí)行完畢之后,concurrent dispatch queue才恢復(fù)過來一般的動作糕殉,追加到該concurrent dispatch queue的處理又開始并行執(zhí)行缨历。
     */
    // 自定義串行隊(duì)列
    dispatch_queue_t serialQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(serialQueue, ^() {
        NSLog(@"dispatch_async--1");
    });
    
    dispatch_async(serialQueue, ^() {
        NSLog(@"dispatch_async--2");
    });
    
    dispatch_barrier_async(serialQueue, ^() {
        NSLog(@"dispatch-barrier_async");
        sleep(1);
    });
    
    // 雖然異步, 但是在串行隊(duì)列中, 會按照順序執(zhí)行
    dispatch_async(serialQueue, ^() {
        NSLog(@"dispatch_async--3");
        sleep(1);
    });
    
    dispatch_async(serialQueue, ^() {
        NSLog(@"dispatch_async--4");
    });
}

#pragma mark - 一次操作
- (void)dispatch_once_t{
    // 一次性執(zhí)行:
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // code to be executed once
    });
}
#pragma mark -延時(shí)執(zhí)行操作
- (void)dispatch_queue_after{
    // 延遲2秒執(zhí)行:
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        // code to be executed on the main queue after delay
    });
}
#pragma mark - 線程組
- (void)dispatch_queue_group{
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
        // 并行執(zhí)行的線程一
    });
    dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
        // 并行執(zhí)行的線程二
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
        
        NSLog(@"current thread = %@", [NSThread currentThread]);
        
    });
}
多線程.png

需要注意的點(diǎn)

  #define LOCK(...) dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER); \
  __VA_ARGS__; \
  dispatch_semaphore_signal(self->_lock);

如何使用

       dispatch_queue_t concurrentQueue =    dispatch_queue_create("www.fangchuang.com", DISPATCH_QUEUE_CONCURRENT);
       dispatch_group_t group = dispatch_group_create();
       _lock = dispatch_semaphore_create(1);
       for (int i = 0; i < 50; i++) {
        //并列隊(duì)列的異步執(zhí)行
        dispatch_group_async(group, concurrentQueue, ^{
            //如果lock的值大于等于1繼續(xù)執(zhí)行,否則(-1)返回
            LOCK(
                 NSLog(@">>>>  %d",i);
            );
        });
    }

如何給一個(gè)線程設(shè)置標(biāo)識符

     dispatch_queue_t MessageDataPrepareQueue(){
     static dispatch_queue_t queue;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
           queue = dispatch_queue_create("DataPrepareSpecificKeyMessage.queue", 0);
           dispatch_queue_set_specific(queue, DispatchMessageDataPrepareSpecificKey, (void *)DispatchMessageDataPrepareSpecificKey, NULL);
    });
          return queue;
    }

UITableView滑動時(shí)并發(fā)其它操作需要注意點(diǎn)

dispatch_sync(MessageDataPrepareQueue(), ^{

    if (dispatch_get_specific(DispatchMessageDataPrepareSpecificKey)) {
        //當(dāng)前隊(duì)列是queue1隊(duì)列糙麦,所以能取到DispatchMessageDataPrepareSpecificKey對應(yīng)的值辛孵,故而執(zhí)行
        //后臺線程處理寬度計(jì)算,處理完之后同步拋到主線程插入
    }else{
       
    }
});

//此時(shí)遇到tableView 正在滑動就延時(shí)操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), MessageDataPrepareQueue(), ^{
    NSLog(@"延時(shí)操作");
});

@synchronized需要注意點(diǎn)

濫用 @synchronized (self) 會很危險(xiǎn)赡磅,因?yàn)樗型綁K都會彼此搶奪同一個(gè)鎖魄缚。要是有很多屬性都這樣寫,那么每個(gè)屬性的同步塊都要等待其他所有同步塊執(zhí)行完畢才能執(zhí)行焚廊,其實(shí)我們只是想要每個(gè)屬性各自獨(dú)立的同步
實(shí)用@synchronized (self)從某種程度上來說冶匹,是線程安全的,但卻無法保證訪問該對象時(shí)是線程安全的咆瘟。當(dāng)然嚼隘,訪問屬性的操作確實(shí)是原子的。實(shí)用屬性時(shí)袒餐,確實(shí)能從中獲取有效值飞蛹,然而在同一個(gè)線程上多次調(diào)用getter方法,每次獲取的結(jié)果卻是未必相同的灸眼。在兩次訪問操作之間卧檐,可能有其他線程寫入了新的值。
解決方案: 將寫入操作和讀取操作放在同一個(gè)線程中執(zhí)行焰宣,保證數(shù)據(jù)同步霉囚。
dispatch_barrier在并發(fā)隊(duì)列中創(chuàng)建一個(gè)同步點(diǎn),當(dāng)并發(fā)隊(duì)列中遇到一個(gè) dispatch_barrier時(shí)匕积,會延時(shí)執(zhí)行該 dispatch_barrier盈罐,等待在 dispatch_barrier之前提交的任務(wù)block執(zhí)行完后才開始執(zhí)行,之后闪唆,并發(fā)隊(duì)列繼續(xù)執(zhí)行后續(xù)block任務(wù)盅粪。
在隊(duì)列中,柵欄塊必須單獨(dú)執(zhí)行苞氮,不能和其他塊并行湾揽。并發(fā)隊(duì)列如果發(fā)現(xiàn)接下來要處理的塊是個(gè)柵欄塊,那么就一直等待當(dāng)前所有并發(fā)塊都執(zhí)行完畢,才會單獨(dú)執(zhí)行這個(gè)柵欄塊库物。等待柵欄塊執(zhí)行過后霸旗,再按正常方式繼續(xù)向下執(zhí)行。

下邊給出案例:銀行賬戶存取案例的優(yōu)化戚揭,保證真正的線程安全
#import <Foundation/Foundation.h>

typedef void(^AccountBalanceBock)();

@interface Account : NSObject

@property (nonatomic ,assign) NSInteger balance;

@property (copy ,nonatomic) AccountBalanceBock accountBalanceBock;

- (void)withdraw:(NSInteger)amount success:(AccountBalanceBock)success;

- (void)deposit:(NSInteger)amount success:(AccountBalanceBock)success;
@end
  
#import "Account.h"

@interface Account ()

@property (nonatomic ,strong) dispatch_queue_t queue;

@property (nonatomic ,assign) NSInteger privateBalance;

@end

@implementation Account

- (Account *)init{
     self = [super init];
     if (self) {
         self.queue = dispatch_queue_create("www.fangchang.com", NULL);
         self.privateBalance = 0;
     }
       return self;
 }

 - (NSInteger)balance{

     dispatch_sync(self.queue, ^{
           _balance = self.privateBalance;
     });
    // 將寫入操作和讀取操作放在同一個(gè)線程中執(zhí)行诱告,保證數(shù)據(jù)同步。
      return _balance;
}

- (void)withdraw:(NSInteger)amount success:(AccountBalanceBock)success{

         NSInteger newBalance = self.privateBalance - amount;
         if (newBalance<0) {
                NSLog(@"當(dāng)前賬戶余額不足100");
               return ;
            }
          sleep(1);
          self.privateBalance = newBalance;
          dispatch_async(dispatch_get_main_queue(), ^{
              if (success!=nil) {
                  success();
              }
          });
 }

- (void)deposit:(NSInteger)amount success:(AccountBalanceBock)success{

    NSInteger newBalance = self.privateBalance + amount;
    self.privateBalance = newBalance;

    dispatch_async(dispatch_get_main_queue(), ^{
        if (success!=nil) {
             success();
        }
   });
}

- (void)setPrivateBalance:(NSInteger)privateBalance{
      dispatch_barrier_async(self.queue, ^{
           _privateBalance = privateBalance;
      });
    // dispatch_barrier在并發(fā)隊(duì)列中創(chuàng)建一個(gè)同步點(diǎn)民晒,當(dāng)并發(fā)隊(duì)列中遇到一個(gè) dispatch_barrier時(shí)精居,會延時(shí)執(zhí)行該 dispatch_barrier,等待在 dispatch_barrier之前提交的任務(wù)block執(zhí)行完后才開始執(zhí)行潜必,之后靴姿,并發(fā)隊(duì)列繼續(xù)執(zhí)行后續(xù)block任務(wù)
}
@end

github 地址:
https://github.com/summerHearts/ThreadSanitizer
https://github.com/summerHearts/iOSTips

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市磁滚,隨后出現(xiàn)的幾起案子佛吓,更是在濱河造成了極大的恐慌,老刑警劉巖垂攘,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件维雇,死亡現(xiàn)場離奇詭異,居然都是意外死亡晒他,警方通過查閱死者的電腦和手機(jī)吱型,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陨仅,“玉大人津滞,你說我怎么就攤上這事〉嗝” “怎么了据沈?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饺蔑。 經(jīng)常有香客問我,道長嗜诀,這世上最難降的妖魔是什么猾警? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮隆敢,結(jié)果婚禮上发皿,老公的妹妹穿的比我還像新娘。我一直安慰自己拂蝎,他們只是感情好穴墅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般玄货。 火紅的嫁衣襯著肌膚如雪皇钞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天松捉,我揣著相機(jī)與錄音夹界,去河邊找鬼。 笑死隘世,一個(gè)胖子當(dāng)著我的面吹牛可柿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丙者,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼复斥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了械媒?” 一聲冷哼從身側(cè)響起永票,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滥沫,沒想到半個(gè)月后侣集,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兰绣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年世分,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缀辩。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡臭埋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出臀玄,到底是詐尸還是另有隱情瓢阴,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布健无,位于F島的核電站荣恐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏累贤。R本人自食惡果不足惜叠穆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望臼膏。 院中可真熱鬧硼被,春花似錦、人聲如沸渗磅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仔掸,卻和暖如春脆贵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嘉汰。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工丹禀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鞋怀。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓双泪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親密似。 傳聞我的和親對象是個(gè)殘疾皇子焙矛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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