第十八章 異常和錯(cuò)誤

異常

異常(exception)就是指必須中斷程序的正常執(zhí)行來進(jìn)行處理的特殊狀態(tài)卢鹦。

編碼時(shí)采取將異常發(fā)生時(shí)的處理和程序原本應(yīng)該執(zhí)行的處理分開進(jìn)行的結(jié)構(gòu),就是異常處理機(jī)制(exception handling mechanism)蓬戚。當(dāng)異常狀況產(chǎn)生時(shí),程序會(huì)自動(dòng)脫離出普通的函數(shù)和方法的調(diào)用殿如,轉(zhuǎn)而執(zhí)行異常處理過程君仆。

Objective-C中的異常處理

利用異常的程序或通過引發(fā)異常來控制動(dòng)作的編程類型并不被推薦忙厌。也就是說凫岖,因設(shè)計(jì)錯(cuò)誤或程序錯(cuò)誤而產(chǎn)生的執(zhí)行時(shí)錯(cuò)誤,在開發(fā)時(shí)就應(yīng)該被去除逢净。

使用OC異常處理機(jī)制的目的:

對調(diào)試起到輔助作用

防止部分異常波及整個(gè)應(yīng)用

異常處理機(jī)制概述

異常句柄和異常處理域

異常發(fā)生時(shí)哥放,為執(zhí)行異常處理而準(zhǔn)備的流程稱為異常句柄(exception handler)。該異常句柄處理的對象的代碼部分稱為異常處理域(exception handling domain)爹土。

異常表示類NSException

通過生成NSException實(shí)例并發(fā)送raise消息甥雕,就可以啟動(dòng)異常處理。這也稱為“產(chǎn)生異痴鸵穑”或“拋出異成缏叮”。NSException實(shí)例稱為異常對象琼娘。

- (void)raise

//向異常對象拋出異常

當(dāng)向NSException類實(shí)例發(fā)送raise消息時(shí)該狀況已經(jīng)發(fā)生了峭弟。但是附鸽,在異常處理機(jī)制方面來看,只要沒有開始異常處理瞒瘸,就不是異常坷备。也就是說,向NSException實(shí)例發(fā)送消息raise這一時(shí)刻和異常發(fā)生被同等看待了情臭。而且有時(shí)也會(huì)將指向NSException的實(shí)例稱為異常省撑。

異常對象包含的信息:

信息

解釋

名稱

為了識別異常而使用的短字符串。判斷是否為應(yīng)該使用異常句柄處理的對象時(shí)使用俯在。使用下面的方法取出:

- (NSString *)name

原因用文字描述異常原因的長字符串竟秫。用如下方法取出:

- (NSString *)reason

用戶字典傳遞與異常相關(guān)的各種信息時(shí)使用的NSDictionary字典。字典中的信息因異常而異朝巫。用如下方法取出:

- (NSDictionary *)userInfo

異常的名字為全局字符串變量鸿摇,被預(yù)先定義在各種類的頭文件中。調(diào)查發(fā)生的異常時(shí)劈猿,將捕捉的異常對象名和這些異常名比較拙吉。而且,像什么樣的情況下發(fā)生什么異常的信息揪荣,在各類的參考文檔中都有詳述筷黔。

異常處理機(jī)制采用如下語法

@try{

/*異常處理域*/

/*在此記述正常處理*/

...

}

@catch(NSException *exception) {

/*異常句柄*/

/*記述異常處理過程。例如顯示錯(cuò)誤消息等*/

...

}

@finally{

/*后處理*/

/*在此記述無論異常發(fā)送與否最后都會(huì)執(zhí)行的代碼*/

...

}

@try必須寫在@catch和@fianlly的前面仗颈。@catch塊可以寫多個(gè)佛舱,也可以不寫,但此時(shí)必須有@finally塊挨决。

變量名exception只在@catch塊內(nèi)有效。

@finally塊不需要時(shí)也可以不寫肆捕。但只要寫了盖高,該塊內(nèi)的代碼一定會(huì)執(zhí)行慎陵。

簡單的異常處理的示例程序:

#import

intmain(intargc,char*argv[]) {

@autoreleasepool{

idarray = [NSMutableArrayarray];

@try{

if(argc ==1)

array = [arrayobjectAtIndex:1];//NSRangeException

else

[arrayaddObject:nil];//NSInvalidArgumentException

NSLog(@"success\n");

}

@catch(NSException *ex) {

NSString*name = [exname];

NSLog(@"Name: %@\n", name);

NSLog(@"Reason: %@\n", [exreason]);

if([nameisEqualToString:NSRangeException])

NSLog(@"Exception was caught successfully.\n");

else

[exraise];//再次拋出異常

}

NSLog(@"main exit");//行尾沒有換行符也沒有關(guān)系。

}

return0;

}

該程序根據(jù)命令行中是否存在參數(shù)而產(chǎn)生不同的異常席纽。生成空數(shù)組撞蚕,取出第一個(gè)不存在的元素時(shí)將產(chǎn)生異常NSRangeException润梯,追加新的元素nil時(shí)將產(chǎn)生異常NSInvalidArgumentException。因?yàn)锧catch塊中捕獲的異常可以訪問ex變量仆救,所以首先顯示異常的名字和原因。接著彤蔽,當(dāng)發(fā)生的異常為NSRangeException時(shí)就顯示能夠捕獲這一消息顿痪,而當(dāng)其他異常發(fā)生時(shí),則向ex發(fā)送raise消息來再次拋出異常蚁袭。這樣以來,NSRangeException以外的異常就會(huì)由運(yùn)行時(shí)系統(tǒng)來處理卖哎。

[ex raise]被執(zhí)行時(shí)删性,會(huì)顯示和普通的運(yùn)行時(shí)錯(cuò)誤發(fā)生時(shí)幾乎相同的消息蹬挺,然后程序異常就終止了。這是因?yàn)檫\(yùn)行時(shí)系統(tǒng)的未捕獲異常句柄(uncaught exception handler)流程捕獲并處理了異常巴帮。異常處理域外部發(fā)生異常時(shí)榕茧,或程序異常句柄中異常處理不能結(jié)束時(shí),未捕獲的異常句柄就會(huì)向終端肢簿,控制臺(tái)或日志文件中打印消息然后終止程序只恨。

但是抬虽,Cocoa應(yīng)用的主線程內(nèi)發(fā)生異常時(shí),NSApplication(UIApplication)實(shí)例將捕獲未處理的異常休涤,所以未捕獲異常句柄并不會(huì)直接終止應(yīng)用。然而序苏,即使應(yīng)用能夠捕捉到捷凄,異常的產(chǎn)生也仍可能會(huì)給應(yīng)用帶來若干影響,導(dǎo)致應(yīng)用之后的處理不能正確執(zhí)行匈睁。

異常的發(fā)生和傳播

異常的傳播

伴隨著程序的執(zhí)行桶错,某個(gè)異常處理域中可能還會(huì)有其他異常處理在執(zhí)行院刁,異常句柄中也可能再次發(fā)生其他異常。

只使用@catch塊不能結(jié)束某個(gè)異常處理時(shí)任岸,為了委托外部異常句柄來處理阅虫,有時(shí)就需要在@catch塊內(nèi)故意拋出異常。像這樣米碰,為了保證異常的正常處理购城,被調(diào)用方向調(diào)用方有序有序傳遞異常的過程,稱為異常傳播(propagation)吴趴。任何異常句柄侮攀,當(dāng)不能被合適處理或在異常處理域外部發(fā)生異常時(shí)兰英,最終都會(huì)由未捕獲異常句柄來處理。

自己觸發(fā)異常

如前所述陨闹,向異常對象發(fā)送raise消息就可以拋出異常,但是寨闹,實(shí)際上使用下面的類NSException的方法會(huì)更加容易君账。

+ (void)raise:(NSString *)name formar:(NSString *)format,...

//將異常名及原因保存成信息并創(chuàng)建臨時(shí)實(shí)例,直接產(chǎn)生異常帖蔓。

也可以自定義異常名并產(chǎn)生新型的異常瞳脓,此時(shí)劫侧,必須起一個(gè)可以和其他異常相區(qū)別的名字。

用@throw語法產(chǎn)生異常

將@throw方法應(yīng)用于NSException實(shí)例写妥,同發(fā)送raise消息是一樣的审姓。

@throwobject;

即便@catch塊內(nèi)沒有參數(shù)也可以使用@throw。此時(shí)扎筒,@catch塊捕捉的異常對象就被視為參數(shù)酬姆,同傳入?yún)?shù)的效果一樣辞色。

將NSException以外的普通對象指定為@throw參數(shù)也可以產(chǎn)生異常,@catch語法中必須要指明該對象的類型层亿。如果對象類型不明確立美,那么使用id類型后,結(jié)果就將捕捉包含NSException在內(nèi)的所有異常琳省。

@catch塊可以被書寫多個(gè)躲撰,但是必須要注意它們的順序拢蛋。這是因?yàn)椋鶕?jù)書寫順序能夠得知用@throw產(chǎn)生異常時(shí)使用的對象和哪個(gè)@catch塊參數(shù)一致快压。

@catch的特殊語法

@catch參數(shù)除了上面介紹的書寫方法外垃瞧,也可以采用下面的方式書寫。即括號內(nèi)不省略脉幢,而是寫三個(gè)點(diǎn)號嗦锐。

@catch(...) {

/*異常句柄*/

}

在需要捕捉異常而不需要知道異常內(nèi)容的情況下奕污,經(jīng)常會(huì)使用該寫法。如果存在其他的@catch塊贾陷,則必須將其書寫為最后的塊嘱根。塊內(nèi)@throw不指定參數(shù)時(shí)儿子,就能傳播異常。

異常傳播和@finally

@catch塊內(nèi)發(fā)生異常時(shí)(或傳播)蒋譬,或者不存在可以捕捉發(fā)生的異常的@catch塊時(shí)愉适,通常就會(huì)將處理移交給外部的異常句柄來執(zhí)行。但如果有@finally塊剂买,那么在向外側(cè)異常句柄移交處理前瞬哼,@finally塊的內(nèi)容先被執(zhí)行。在沒發(fā)生異常時(shí)坐慰,@finally會(huì)在@try塊之后執(zhí)行结胀,而當(dāng)異常不向外側(cè)傳播時(shí),@finally塊必須緊挨著@catch塊執(zhí)行攀操。所以秸抚,這里就要書寫實(shí)例釋放或文件關(guān)閉等必須要執(zhí)行的后處理耸别。如下圖。如果不捕捉異常而只想執(zhí)行后處理慈迈,也可以不寫@catch省有。

異常處理程序的注意點(diǎn)

遞歸調(diào)用(函數(shù)調(diào)用)中發(fā)生異常時(shí)蠢沿,處理有時(shí)就會(huì)跳過內(nèi)側(cè)的方法而轉(zhuǎn)移到外側(cè)的異常句柄中進(jìn)行。如圖恤磷。如果處理被中斷時(shí)務(wù)必進(jìn)行后處理野宜。

引用計(jì)數(shù)管理和異常匈子。不能保證對象被正確釋放。因此游岳,在OC中,寫代碼時(shí)不能以使用異常處理機(jī)制為前提喷户。

關(guān)于C語言中的全局跳轉(zhuǎn)函數(shù)晌区。C語言有兩個(gè)函數(shù)setjmp()和longjmp()朗若,它們都可以從函數(shù)調(diào)用的深層遞歸中返回昌罩。但是,異常處理機(jī)制在實(shí)現(xiàn)時(shí)使用了這些功能遣总,所以異常處理機(jī)制和這些跳轉(zhuǎn)函數(shù)不可以同時(shí)使用轨功。

斷言

斷言是什么

在程序中書寫程序必須滿足的條件古涧,當(dāng)條件被破壞時(shí)就觸發(fā)異常的結(jié)構(gòu)稱為斷言(assertion)。

斷言使用宏來書寫菇爪,定義在NSException.h中凳宙。

斷言宏的參數(shù)中寫著必須為真的條件职祷。

NASSert(x > y, *@"illegal values x(%d) & y(%d)", x, y);

條件為假時(shí),異常NSInternalInconsistencyException就會(huì)被觸發(fā)削葱。

編譯時(shí)定義了NS_BLOCK_ASSERTIONS宏時(shí)析砸,斷言不會(huì)被寫入代碼爆袍,而因?yàn)闆]有寫入作郭,就會(huì)被當(dāng)成空字符串處理夹攒。于是在編譯完成后的程序時(shí)胁塞,就要在編譯器的選項(xiàng)中加入-DNS_BLOCK_ASSERTIONS啸罢。選項(xiàng)-D的作用是可以從命令行定義宏,就不需要特意在文件中書寫#define了允懂。

斷言宏

斷言宏可以在OC方法內(nèi)以及C函數(shù)內(nèi)使用衩匣。斷言條件為假時(shí)琅捏,如果是在函數(shù)內(nèi),那么就用函數(shù)名來表示置侍;而如果是在方法內(nèi)拦焚,那么就用方法名來表示赎败。

首先,只在條件為真時(shí)使用的宏有兩個(gè):

NSParameterAssert(condition)….在方法內(nèi)使用

NSCParameterAssert(condition)…在函數(shù)內(nèi)使用

此外還有宏可以在條件為假時(shí)傳遞觸發(fā)的異常据忘,以及生成用來說明異常的字符串勇吊。它們和printf()一樣窍仰,取得格式字符串和對應(yīng)的參數(shù)。使用目前為止的C語言規(guī)范尚不可以定義參數(shù)個(gè)數(shù)不確定的宏针史,而在新的規(guī)范中是可以的啄枕。

在方法內(nèi)使用

NSAssert(condition,NSString *description [,arg,…])

在函數(shù)內(nèi)使用

NSCAssert(condition,Nsstring *description[,arg,…])

錯(cuò)誤處理

錯(cuò)誤處理結(jié)構(gòu)的目的

在Cocoa環(huán)境下,為了能夠統(tǒng)一表示錯(cuò)誤的種類和消息泌参,可以使用NSError沽一。簡單來說窟绷,NSError持有錯(cuò)誤說明和錯(cuò)誤的處理方法的相關(guān)信息兼蜈。

表示錯(cuò)誤的類NSError的使用方法

信息

解釋

導(dǎo)致錯(cuò)誤的技術(shù)因素拙友。例如,顯示Cocoa辐棒,Carbon漾根,Unix等中的誰的API相關(guān)的字符串鲫竞。用下面方法取出:

- (NSString *) domain

代碼表示錯(cuò)誤類型的整數(shù)值从绘。需要注意的是代碼的意義可根據(jù)域而發(fā)生變化。用下面的方法取出:

- (NSInteger)code

用戶字典為得到有關(guān)錯(cuò)誤的各種信息而使用的字典對象陕截。字典中保存的信息隨錯(cuò)誤而不同农曲。用下面的方法取出:

- (NSDictionary *)userInfo

如下所示驻债,準(zhǔn)備好保存的實(shí)例變量,并使用&運(yùn)算符指向該地址即可驯妄。發(fā)生指定的文件不存在等錯(cuò)誤時(shí)青扔,代入錯(cuò)誤對象給變量err。如果沒有發(fā)生錯(cuò)誤則不帶入對象谈息。因此為了明確表示錯(cuò)誤沒有發(fā)生侠仇,應(yīng)該養(yǎng)成預(yù)先為變量err代入nil的操作習(xí)慣犁珠。然而使用ARC管理內(nèi)存時(shí)犁享,方法內(nèi)的自動(dòng)變量地址必須將(NSError**)類型的參數(shù)指定為nil。

NSString*path, *contents;

NSError*err;

...

err =nil;

contents = [NSString stringWithContentsOfFile:path encoding:NSShiftJISStringEncoding error:&err];

獲取錯(cuò)誤對象的信息

為了獲得表示錯(cuò)誤內(nèi)容的消息字符串桨吊,可向NSError實(shí)例發(fā)送下面的消息视乐。沒有必要直接訪問用戶字典或域敢茁。

- (NSString *)localizedDescription

//返回說明錯(cuò)誤的字符串卷要。字符串被本地化,不會(huì)返回nil奕枝。用戶字典中如果存在NSLocalizedDescriptionKey鍵的對象隘道,則返回該對象。

- (NSString *)localizedFailureReason

//顯示錯(cuò)誤產(chǎn)生的原因忘晤,返回本地化的短字符串设塔。有時(shí)返回nil远舅。用戶字典中如果存在NSLocalizedFailureReasonErrorKey鍵的對象图柏,則返回該對象。

- (NSString *)localizedRecoverySuggestion

//顯示錯(cuò)誤的處理方法或建議例诀,返回本地化的短字符串裁着。有時(shí)返回nil繁涂。用戶字典中如果存在NSLocalizedRecoverySuggestionErrorKey鍵的對象爆土,則返回該對象诸蚕。

生成自定義錯(cuò)誤對象

與異常相同背犯,自己也可以生成NSError實(shí)例≈迅В可以使用下面的簡易常數(shù)類妄均。

+ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(nullableNSDictionary *)dict

//指定域名丰包,錯(cuò)誤代碼和用戶字典后創(chuàng)建錯(cuò)誤對象。用戶字典為nil也沒有關(guān)系邑彪,域名必須要指定。典型的錯(cuò)誤域名如下所示矩动。

域名

解釋

頭文件

NSCocoaErrorDomain與Cocoa環(huán)境相關(guān)的錯(cuò)誤Foundation/FoundationErrors.h

AppKit/AppKitErrors.h

CoreData/CoreDataErrors.h

NSPOSIXErrorDomain

與Unix環(huán)境相關(guān)的錯(cuò)誤sys/errno.h

NSMachErrorDomain

與Mach核相關(guān)的錯(cuò)誤mach/kern_return.h

返回新創(chuàng)建的錯(cuò)誤對象時(shí)释漆,如果錯(cuò)誤原因和上述任一個(gè)域相同男图,就可以直接使用域和錯(cuò)誤代碼享言。在Mac OS環(huán)境下,用戶字典即使為nil荧琼,只要指定了域名和錯(cuò)誤代碼命锄,多數(shù)情況下警告面板中也會(huì)顯示日語的錯(cuò)誤消息偏化。

錯(cuò)誤反應(yīng)鏈

通過將NSError結(jié)合應(yīng)用框架來使用侦讨,就可以在GUI環(huán)境中靈活的進(jìn)行錯(cuò)誤處理。核心模塊是錯(cuò)誤反應(yīng)鏈(error-responder chain)骗污。

錯(cuò)誤反應(yīng)鏈的結(jié)構(gòu)

錯(cuò)誤反應(yīng)鏈與反應(yīng)鏈同樣沈条,是位于底層的組件指向上層組件的對象(反應(yīng)器)的連接蜡歹。

當(dāng)與某個(gè)組件相關(guān)的錯(cuò)誤發(fā)生時(shí)月而,會(huì)將錯(cuò)誤對象作為參數(shù)將消息presentError:發(fā)送給該組件。于是錯(cuò)誤對象就會(huì)從該組件開始被轉(zhuǎn)發(fā)給上層的組件仲翎。最終由窗體發(fā)送給NSApplication實(shí)例溯香,錯(cuò)誤提示和恢復(fù)被執(zhí)行。

錯(cuò)誤對象的更改和恢復(fù)

因發(fā)生錯(cuò)誤傳遞的錯(cuò)誤對象以及用戶字典是常數(shù)對象结笨,所以willPresentError:必須要返回一個(gè)新創(chuàng)建的錯(cuò)誤對象。而且原錯(cuò)誤對象使用新錯(cuò)誤對象用戶字典中NSUnderlyingErrorKey鍵并保存它湿镀。

包含多個(gè)字符串時(shí)炕吸,第一個(gè)字符串在面板的最右側(cè)(默認(rèn)),然后是右邊第二個(gè)勉痴,按照此順序排列赫模。也可能返回nil,此時(shí)警告面板中只顯示“OK”鍵蒸矛。

接著瀑罗,在取得按鍵的選擇結(jié)果后,指定對象來執(zhí)行恢復(fù)處理雏掠。該對象就稱為恢復(fù)嘗試對象(recovery attempter)。

恢復(fù)嘗試對象可以是任意類的實(shí)例乡话,但為了進(jìn)行恢復(fù)摧玫,需要實(shí)現(xiàn)NSErrorRecoveryAttempting非正式協(xié)議的其中任意一個(gè)方法。該非正式協(xié)議在Foundation/NSError.h中聲明绑青。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诬像,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子时迫,更是在濱河造成了極大的恐慌颅停,老刑警劉巖谓晌,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掠拳,死亡現(xiàn)場離奇詭異,居然都是意外死亡纸肉,警方通過查閱死者的電腦和手機(jī)溺欧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柏肪,“玉大人姐刁,你說我怎么就攤上這事》澄叮” “怎么了聂使?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵壁拉,是天一觀的道長。 經(jīng)常有香客問我柏靶,道長弃理,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任屎蜓,我火速辦了婚禮痘昌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘炬转。我一直安慰自己辆苔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布扼劈。 她就那樣靜靜地躺著驻啤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荐吵。 梳的紋絲不亂的頭發(fā)上街佑,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機(jī)與錄音捍靠,去河邊找鬼沐旨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛榨婆,可吹牛的內(nèi)容都是我干的磁携。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼良风,長吁一口氣:“原來是場噩夢啊……” “哼谊迄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烟央,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤统诺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后疑俭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粮呢,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年钞艇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啄寡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,561評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哩照,死狀恐怖挺物,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情飘弧,我是刑警寧澤识藤,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布砚著,位于F島的核電站,受9級特大地震影響痴昧,放射性物質(zhì)發(fā)生泄漏赖草。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一剪个、第九天 我趴在偏房一處隱蔽的房頂上張望秧骑。 院中可真熱鬧,春花似錦扣囊、人聲如沸乎折。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骂澄。三九已至,卻和暖如春惕虑,著一層夾襖步出監(jiān)牢的瞬間坟冲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工溃蔫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留健提,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓伟叛,卻偏偏與公主長得像私痹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子统刮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評論 2 359

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