iOS多線程相關(guān)面試題

首先要說(shuō)明一下纪蜒,下面所有面試題調(diào)用的方法(比如第一個(gè)面試題調(diào)用的方法是interview1)都是在主線程中調(diào)用的。

作為一個(gè)開(kāi)發(fā)者莲趣,有一個(gè)學(xué)習(xí)的氛圍跟一個(gè)交流圈子特別重要样悟,這是一個(gè)我的iOS開(kāi)發(fā)交流群:130 595 548,不管你是大牛還是小白都?xì)g迎入駐 梆暖,讓我們一起進(jìn)步伞访,共同發(fā)展!(群內(nèi)會(huì)免費(fèi)提供一些群主收藏的免費(fèi)學(xué)習(xí)書(shū)籍資料以及整理好的幾百道面試題和答案文檔:洳怠)

  1. 面試題1
- (void)interview1{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
        [self performSelector:@selector(test1) withObject:nil afterDelay:.0f];
        NSLog(@"3---%@",[NSThread currentThread]);
    });
}

- (void)test1{
    NSLog(@"2---%@",[NSThread currentThread]);
}

// ***************打印結(jié)果***************
2019-12-30 17:37:58.427558+0800 MultithreadingDemo[39113:4277962] 1---<NSThread: 0x600001922d40>{number = 6, name = (null)}
2019-12-30 17:37:58.427659+0800 MultithreadingDemo[39113:4277962] 3---<NSThread: 0x600001922d40>{number = 6, name = (null)}

解釋: performSelector:withObject:afterDelay:的本質(zhì)是往Runloop中添加定時(shí)器(即使延時(shí)時(shí)間是0秒)厚掷。由于異步函數(shù)dispatch_async是開(kāi)啟一個(gè)新的子線程去執(zhí)行任務(wù),而子線程默認(rèn)是沒(méi)有啟動(dòng)Runloop的级解,所以并不會(huì)執(zhí)行test1方法冒黑。
我們可以手動(dòng)啟動(dòng)runloop來(lái)確保test1被調(diào)用,也就是在block里面添加一行代碼[[NSRunLoop currentRunLoop] run];勤哗。

如果把異步函數(shù)改為同步函數(shù)抡爹,我們?cè)賮?lái)看下運(yùn)行結(jié)果:

- (void)interview1{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
        [self performSelector:@selector(test1) withObject:nil afterDelay:.0f];
        NSLog(@"3---%@",[NSThread currentThread]);
    });
}

- (void)test1{
    NSLog(@"2---%@",[NSThread currentThread]);
}

// ***************打印結(jié)果***************
2019-12-30 17:47:01.936609+0800 MultithreadingDemo[39150:4282068] 1---<NSThread: 0x6000009660c0>{number = 1, name = main}
2019-12-30 17:47:01.936724+0800 MultithreadingDemo[39150:4282068] 3---<NSThread: 0x6000009660c0>{number = 1, name = main}
2019-12-30 17:47:01.936904+0800 MultithreadingDemo[39150:4282068] 2---<NSThread: 0x6000009660c0>{number = 1, name = main}

解釋: 同步函數(shù)添加的任務(wù)是在當(dāng)前線程中執(zhí)行,當(dāng)前線程就是主線程芒划,而主線程的Runloop是啟動(dòng)的冬竟,所以test1會(huì)調(diào)用。雖然延遲時(shí)間時(shí)0秒民逼,但是添加到Runloop中的計(jì)時(shí)器不是立馬觸發(fā)的泵殴,而是要先喚醒Runloop,這是需要消耗一定時(shí)間的拼苍,所以會(huì)先打印3再打印2笑诅。

我們?cè)侔裵erformSelector:withObject:afterDelay:替換成performSelector:withObject:看看運(yùn)行結(jié)果:

- (void)interview1{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
        [self performSelector:@selector(test1) withObject:nil];
        NSLog(@"3---%@",[NSThread currentThread]);
    });
}

- (void)test1{
    NSLog(@"2---%@",[NSThread currentThread]);
}

// ***************打印結(jié)果***************
2019-12-30 17:54:18.072035+0800 MultithreadingDemo[39183:4285659] 1---<NSThread: 0x60000303c300>{number = 3, name = (null)}
2019-12-30 17:54:18.072136+0800 MultithreadingDemo[39183:4285659] 2---<NSThread: 0x60000303c300>{number = 3, name = (null)}
2019-12-30 17:54:18.072215+0800 MultithreadingDemo[39183:4285659] 3---<NSThread: 0x60000303c300>{number = 3, name = (null)}

解釋: performSelector:withObject:函數(shù)是不涉及到計(jì)時(shí)器的,所以不會(huì)添加到Runloop中,所以是按照1吆你、2弦叶、3的順序執(zhí)行。
注意:performSelector系列方法中只要是方法名中包含afterDelay妇多、waitUntilDone的都是和計(jì)時(shí)器有關(guān)的伤哺,都要注意前面出現(xiàn)的這些問(wèn)題。

  1. 面試題2
- (void)interview2{
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
       NSLog(@"1---%@",[NSThread currentThread]);
    }];
    [thread start];
    
    [self performSelector:@selector(test2) onThread:thread withObject:nil waitUntilDone:YES];
}

- (void)test2{
    NSLog(@"2---%@",[NSThread currentThread]);
}

// ***************運(yùn)行結(jié)果(閃退)***************
2019-12-31 08:36:07.132133+0800 MultithreadingDemo[40268:4493885] 1---<NSThread: 0x6000010d9880>{number = 6, name = (null)}
2019-12-31 08:36:07.432190+0800 MultithreadingDemo[40268:4493455] *** Terminating app due to uncaught exception 'NSDestinationInvalidException', reason: '*** -[Interview performSelector:onThread:withObject:waitUntilDone:modes:]: target thread exited while waiting for the perform'

解釋: 從運(yùn)行結(jié)果可以看出閃退的原因是target thread exited(目標(biāo)線程退出)砌梆。因?yàn)閠est2方法是在線程thread上執(zhí)行的默责,但是線程thread在執(zhí)行完NSLog(@"1---%@",[NSThread currentThread]);這句代碼后就結(jié)束了,所以等到執(zhí)行test2方法時(shí)線程thread已經(jīng)不存在了(嚴(yán)格來(lái)說(shuō)是線程對(duì)象是還存在的咸包,只是已經(jīng)失活了桃序,不能再執(zhí)行任務(wù)了)。
如果想要代碼能正常運(yùn)行烂瘫,我們可以利用Runloop知識(shí)來(lái)泵叫埽活線程。先向當(dāng)前runloop中添加一個(gè)source(如果runloop中一個(gè)source坟比、NSTime或Obserer都沒(méi)有的話就會(huì)退出)芦鳍,然后啟動(dòng)runloop。也就是在線程thread的block中添加2行代碼葛账,如下所示:

NSThread *thread = [[NSThread alloc] initWithBlock:^{
       NSLog(@"1---%@",[NSThread currentThread]);
        
        // 線程蹦疲活
        // 先向當(dāng)前runloop中添加一個(gè)source(如果runloop中一個(gè)source、NSTime或Obserer都沒(méi)有的話就會(huì)退出)
        [[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSRunLoopCommonModes];
        // 然后啟動(dòng)runloop
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }];
  1. 面試題3
- (void)interview3{
    NSLog(@"執(zhí)行任務(wù)1--%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"執(zhí)行任務(wù)2--%@",[NSThread currentThread]);
    });
    
    NSLog(@"執(zhí)行任務(wù)3--%@",[NSThread currentThread]);
}

運(yùn)行結(jié)果:
執(zhí)行完任務(wù)1后就被卡死了籍琳。
解釋:
interview3方法是在主線程中執(zhí)行菲宴,執(zhí)行完任務(wù)1后,通過(guò)同步函數(shù)向主隊(duì)列(串行隊(duì)列)添加任務(wù)2趋急,由于同步添加的任務(wù)必須馬上執(zhí)行喝峦,而串行隊(duì)列中當(dāng)前任務(wù)(interview3)還沒(méi)執(zhí)行完,就沒(méi)法安排任務(wù)2執(zhí)行呜达,所以要等當(dāng)前正在執(zhí)行的任務(wù)(interview3)執(zhí)行完了后才能執(zhí)行任務(wù)2谣蠢,而interview3又要等任務(wù)2執(zhí)行完了才會(huì)繼續(xù)往下執(zhí)行,這樣就造成了相互等待而死鎖查近。

  1. 面試題4
- (void)interview4{
    NSLog(@"執(zhí)行任務(wù)1--%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)2--%@",[NSThread currentThread]);
    });
    
    NSLog(@"執(zhí)行任務(wù)3--%@",[NSThread currentThread]);
}

// ***************打印結(jié)果***************
2019-12-31 10:06:37.782135+0800 MultithreadingDemo[41281:4538099] 執(zhí)行任務(wù)1--<NSThread: 0x600003cd1d80>{number = 1, name = main}
2019-12-31 10:06:37.782244+0800 MultithreadingDemo[41281:4538099] 執(zhí)行任務(wù)3--<NSThread: 0x600003cd1d80>{number = 1, name = main}
2019-12-31 10:06:37.782574+0800 MultithreadingDemo[41281:4538099] 執(zhí)行任務(wù)2--<NSThread: 0x600003cd1d80>{number = 1, name = main}

解釋:
這和前面一個(gè)面試題相比只是把同步函數(shù)換成了異步函數(shù)眉踱。執(zhí)行完任務(wù)1后,通過(guò)異步函數(shù)添加任務(wù)2霜威,雖然異步函數(shù)有開(kāi)啟子線程的能力谈喳,但是由于是在主隊(duì)列中,主隊(duì)列的任務(wù)都是在主線程中執(zhí)行侥祭,所以并不會(huì)開(kāi)啟子線程叁执。由于是異步函數(shù)添加的任務(wù)2,所以不必等待任務(wù)2就可以繼續(xù)往下執(zhí)行矮冬,等當(dāng)前任務(wù)(interview4)完成后串行隊(duì)列再安排執(zhí)行任務(wù)2谈宛。所以并不會(huì)造成死鎖。

  1. 面試題5
- (void)interview5{
    NSLog(@"執(zhí)行任務(wù)1--%@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)2--%@",[NSThread currentThread]);
        
        dispatch_sync(queue, ^{
            NSLog(@"執(zhí)行任務(wù)3--%@",[NSThread currentThread]);
        });
    
        NSLog(@"執(zhí)行任務(wù)4--%@",[NSThread currentThread]);
    });
    
    NSLog(@"執(zhí)行任務(wù)5--%@",[NSThread currentThread]);

// ***************打印結(jié)果(打印1胎署、5吆录、2后卡死)***************    
2019-12-31 10:45:29.071774+0800 MultithreadingDemo[41379:4551961] 執(zhí)行任務(wù)1--<NSThread: 0x6000038460c0>{number = 1, name = main}
2019-12-31 10:45:29.071923+0800 MultithreadingDemo[41379:4551961] 執(zhí)行任務(wù)5--<NSThread: 0x6000038460c0>{number = 1, name = main}
2019-12-31 10:45:29.071932+0800 MultithreadingDemo[41379:4552048] 執(zhí)行任務(wù)2--<NSThread: 0x600003824f40>{number = 6, name = (null)}
}

解釋: 首先打印任務(wù)1,然后自己創(chuàng)建了一個(gè)串行隊(duì)列琼牧,并通過(guò)異步函數(shù)向這個(gè)隊(duì)列中添加一個(gè)任務(wù)塊(block1)恢筝,異步函數(shù)會(huì)開(kāi)啟一個(gè)子線程并將block1放入子線程中去執(zhí)行,開(kāi)啟子線程是要耗時(shí)的巨坊,而且異步任務(wù)不需要等待就可以繼續(xù)執(zhí)行它后面的代碼撬槽,所以打印任務(wù)5在block1前面執(zhí)行。
再來(lái)看block1任務(wù)塊趾撵,先打印任務(wù)2侄柔,然后通過(guò)同步函數(shù)添加的block2任務(wù)塊需要立馬執(zhí)行,而block1所在的隊(duì)列是串行隊(duì)列占调,block1任務(wù)塊還沒(méi)執(zhí)行完暂题,所以要先等block1執(zhí)行,而block1又要等block2執(zhí)行完了才能繼續(xù)往下執(zhí)行究珊,所以就造成了相互等待而死鎖薪者。

  1. 面試題6
- (void)interview6{

    NSLog(@"執(zhí)行任務(wù)1--%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("myqueu2", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)2--%@",[NSThread currentThread]);
        
        dispatch_sync(queue2, ^{
            NSLog(@"執(zhí)行任務(wù)3--%@",[NSThread currentThread]);
        });
        
        NSLog(@"執(zhí)行任務(wù)4--%@",[NSThread currentThread]);
    });
    
    NSLog(@"執(zhí)行任務(wù)5--%@",[NSThread currentThread]);
}

// ***************打印結(jié)果*************** 
2019-12-31 11:01:47.812260+0800 MultithreadingDemo[41405:4557566] 執(zhí)行任務(wù)1--<NSThread: 0x600002836180>{number = 1, name = main}
2019-12-31 11:01:47.812470+0800 MultithreadingDemo[41405:4557566] 執(zhí)行任務(wù)5--<NSThread: 0x600002836180>{number = 1, name = main}
2019-12-31 11:01:47.812488+0800 MultithreadingDemo[41405:4557684] 執(zhí)行任務(wù)2--<NSThread: 0x600002830980>{number = 5, name = (null)}
2019-12-31 11:01:47.812567+0800 MultithreadingDemo[41405:4557684] 執(zhí)行任務(wù)3--<NSThread: 0x600002830980>{number = 5, name = (null)}
2019-12-31 11:01:47.812648+0800 MultithreadingDemo[41405:4557684] 執(zhí)行任務(wù)4--<NSThread: 0x600002830980>{number = 5, name = (null)}

解釋:
這個(gè)和面試題5相比就是新加了一個(gè)隊(duì)列(不管是串行隊(duì)列還是并發(fā)隊(duì)列都一樣),block1任務(wù)塊和block2任務(wù)塊分別放在不同的隊(duì)列中剿涮。
先打印任務(wù)1再打印任務(wù)5和前面是一樣的言津。然后異步函數(shù)會(huì)開(kāi)啟子線程去執(zhí)行block1任務(wù)塊,block1中先打印任務(wù)2幔虏,然后通過(guò)同步函數(shù)向另一個(gè)隊(duì)列中添加block2任務(wù)塊纺念,由于兩個(gè)block屬于不同的隊(duì)列,block2可以立馬被安排執(zhí)行而不會(huì)死鎖想括,所以接著是打印任務(wù)3陷谱,最后打印任務(wù)4。

  1. 面試題7
- (void)interview7{
    NSLog(@"執(zhí)行任務(wù)1--%@",[NSThread currentThread]);
    
    dispatch_queue_t queue = dispatch_queue_create("myqueu", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"執(zhí)行任務(wù)2--%@",[NSThread currentThread]);
        
        dispatch_sync(queue, ^{
            NSLog(@"執(zhí)行任務(wù)3--%@",[NSThread currentThread]);
        });
        
        NSLog(@"執(zhí)行任務(wù)4--%@",[NSThread currentThread]);
    });
    
    NSLog(@"執(zhí)行任務(wù)5--%@",[NSThread currentThread]);
}

// ***************打印結(jié)果***************
2019-12-31 11:14:27.690008+0800 MultithreadingDemo[41445:4562142] 執(zhí)行任務(wù)1--<NSThread: 0x6000011badc0>{number = 1, name = main}
2019-12-31 11:14:27.690102+0800 MultithreadingDemo[41445:4562142] 執(zhí)行任務(wù)5--<NSThread: 0x6000011badc0>{number = 1, name = main}
2019-12-31 11:14:27.690122+0800 MultithreadingDemo[41445:4562301] 執(zhí)行任務(wù)2--<NSThread: 0x6000011f5900>{number = 3, name = (null)}
2019-12-31 11:14:27.690202+0800 MultithreadingDemo[41445:4562301] 執(zhí)行任務(wù)3--<NSThread: 0x6000011f5900>{number = 3, name = (null)}
2019-12-31 11:14:27.690285+0800 MultithreadingDemo[41445:4562301] 執(zhí)行任務(wù)4--<NSThread: 0x6000011f5900>{number = 3, name = (null)}

解釋:
這個(gè)和面試題5相比是把串行隊(duì)列換成了并發(fā)隊(duì)列瑟蜈。
先打印任務(wù)1再打印任務(wù)5和前面是一樣的烟逊。然后異步函數(shù)會(huì)開(kāi)啟子線程去執(zhí)行block1任務(wù)塊,block1中先打印任務(wù)2铺根,然后通過(guò)同步函數(shù)向并發(fā)隊(duì)列中添加block2任務(wù)塊宪躯,并發(fā)隊(duì)列不需要等前一個(gè)任務(wù)完成就可以安排下一個(gè)任務(wù)執(zhí)行,所以block2可以立馬執(zhí)行打印任務(wù)3位迂,最后再打印任務(wù)4访雪。

作為一個(gè)開(kāi)發(fā)者详瑞,有一個(gè)學(xué)習(xí)的氛圍跟一個(gè)交流圈子特別重要,這是一個(gè)我的iOS開(kāi)發(fā)交流群:130595548臣缀,不管你是大牛還是小白都?xì)g迎入駐 坝橡,讓我們一起進(jìn)步,共同發(fā)展>谩(群內(nèi)會(huì)免費(fèi)提供一些群主收藏的免費(fèi)學(xué)習(xí)書(shū)籍資料以及整理好的幾百道面試題和答案文檔F攀摹)

?著作權(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)容