iOSKVC 底層原理探索

一声旺,概念

KVC(Key-value coding)鍵值編碼尺锚,單看這個(gè)名字可能不太好理解吼蚁。其實(shí)翻譯一下就很簡(jiǎn)單了贮缕,就是指iOS的開(kāi)發(fā)中辙谜,可以允許開(kāi)發(fā)者通過(guò)Key名直接訪問(wèn)對(duì)象的屬性,或者給對(duì)象的屬性賦值感昼。而不需要調(diào)用明確的存取方法装哆。這樣就可以在運(yùn)行時(shí)動(dòng)態(tài)地訪問(wèn)和修改對(duì)象的屬性。而不是在編譯時(shí)確定定嗓,這也是iOS開(kāi)發(fā)中的黑魔法之一蜕琴。很多高級(jí)的iOS開(kāi)發(fā)技巧都是基于KVC實(shí)現(xiàn)的。

二宵溅,KVC在iOS中的定義

無(wú)論是Swift還是Objective-C奸绷,KVC的定義都是對(duì)NSObject的擴(kuò)展來(lái)實(shí)現(xiàn)的(Objective-C中有個(gè)顯式的NSKeyValueCoding類別名,而Swift沒(méi)有层玲,也不需要)号醉。所以對(duì)于所有繼承了NSObject的類型,也就是幾乎所有的Objective-C對(duì)象都能使用KVC(一些純Swift類和結(jié)構(gòu)體是不支持KVC的)辛块,下面是KVC最為重要的四個(gè)方法

- (nullable id)valueForKey:(NSString *)key;                          //直接通過(guò)Key來(lái)取值
- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通過(guò)Key來(lái)設(shè)值
- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通過(guò)KeyPath來(lái)取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通過(guò)KeyPath來(lái)設(shè)值

當(dāng)然因?yàn)镵VC 的定義來(lái)自于基礎(chǔ)框架的Foundation中畔派,所以沒(méi)有開(kāi)源,也就看不到具體代碼的實(shí)現(xiàn)和原來(lái)润绵,所以需要我們借助官方文章來(lái)進(jìn)一步學(xué)習(xí)和了解线椰。

當(dāng)然NSKeyValueCoding類別中還有其他的一些方法,下面列舉一些

+ (BOOL)accessInstanceVariablesDirectly;
//默認(rèn)返回YES尘盼,表示如果沒(méi)有找到Set<Key>方法的話憨愉,會(huì)按照_key烦绳,_iskey,key配紫,iskey的順序搜索成員径密,設(shè)置成NO就不這樣搜索

- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//KVC提供屬性值正確性驗(yàn)證的API,它可以用來(lái)檢查set的值是否正確躺孝、為不正確的值做一個(gè)替換值或者拒絕設(shè)置新值并返回錯(cuò)誤原因享扔。

- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
//這是集合操作的API,里面還有一系列這樣的API植袍,如果屬性是一個(gè)NSMutableArray惧眠,那么可以用這個(gè)方法來(lái)返回。

- (nullable id)valueForUndefinedKey:(NSString *)key;
//如果Key不存在于个,且沒(méi)有KVC無(wú)法搜索到任何和Key有關(guān)的字段或者屬性氛魁,則會(huì)調(diào)用這個(gè)方法,默認(rèn)是拋出異常厅篓。

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//和上一個(gè)方法一樣呆盖,但這個(gè)方法是設(shè)值。

- (void)setNilValueForKey:(NSString *)key;
//如果你在SetValue方法時(shí)面給Value傳nil贷笛,則會(huì)調(diào)用這個(gè)方法

- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
//輸入一組key,返回該組key對(duì)應(yīng)的Value应又,再轉(zhuǎn)成字典返回,用于將Model轉(zhuǎn)到字典乏苦。

上面的這些方法在碰到特殊情況或者有特殊需求還是會(huì)用到的株扛,所以也是可以了解一下。后面的代碼示例會(huì)有講到其中的一些方法汇荐。
同時(shí)蘋(píng)果對(duì)一些容器類比如NSArray或者NSSet等洞就,KVC有著特殊的實(shí)現(xiàn)。建議有基礎(chǔ)的或者英文好的開(kāi)發(fā)者直接去看蘋(píng)果的官方文檔掀淘,相信你會(huì)對(duì)KVC的理解更上一個(gè)臺(tái)階旬蟋。

三,KVC是怎么尋找Key

KVC是怎么使用的革娄,我相信絕大多數(shù)的開(kāi)發(fā)者都很清楚倾贰,我在這里就不再寫(xiě)簡(jiǎn)單的使用KVC來(lái)設(shè)值和取值的代碼了,首先我們來(lái)探討KVC在內(nèi)部是按什么樣的順序來(lái)尋找key的拦惋。


setValue for Key.png

當(dāng)調(diào)用setValue:屬性值 forKey:@”name“的代碼時(shí)匆浙,底層的執(zhí)行機(jī)制如下:

  • 1 程序優(yōu)先調(diào)用set<Key>:屬性值方法,代碼通過(guò)setter方法完成設(shè)置厕妖。注意首尼,這里的<key>是指成員變量名,首字母大小寫(xiě)要符合KVC的命名規(guī)則,下同
  • 2 如果沒(méi)有找到setName:方法软能,KVC機(jī)制會(huì)檢查+ (BOOL)accessInstanceVariablesDirectly方法有沒(méi)有返回YES迎捺,默認(rèn)該方法會(huì)返回YES,如果你重寫(xiě)了該方法讓其返回NO的話查排,那么在這一步KVC會(huì)執(zhí)行setValue:forUndefinedKey:方法凳枝,不過(guò)一般開(kāi)發(fā)者不會(huì)這么做。所以KVC機(jī)制會(huì)搜索該類里面有沒(méi)有名為_<key>的成員變量雹嗦,無(wú)論該變量是在類接口處定義,還是在類實(shí)現(xiàn)處定義合是,也無(wú)論用了什么樣的訪問(wèn)修飾符了罪,只在存在以_<key>命名的變量,KVC都可以對(duì)該成員變量賦值聪全。
  • 3 如果該類即沒(méi)有set<key>:方法泊藕,也沒(méi)有_<key>成員變量,KVC機(jī)制會(huì)搜索_is<Key>的成員變量难礼。
  • 4 和上面一樣娃圆,如果該類即沒(méi)有set<Key>:方法,也沒(méi)有_<key>和_is<Key>成員變量蛾茉,KVC機(jī)制再會(huì)繼續(xù)搜索<key>is<Key>的成員變量讼呢。再給它們賦值。
  • 5 如果上面列出的方法或者成員變量都不存在谦炬,系統(tǒng)將會(huì)執(zhí)行該對(duì)象的setValue:forUndefinedKey:方法悦屏,默認(rèn)是拋出異常。

如果開(kāi)發(fā)者想讓這個(gè)類禁用KVC里键思,那么重寫(xiě)+ (BOOL)accessInstanceVariablesDirectly方法讓其返回NO即可础爬,這樣的話如果KVC沒(méi)有找到set<Key>:屬性名時(shí),會(huì)直接用setValue:forUndefinedKey:方法吼鳞。

3.1 代碼驗(yàn)證賦值過(guò)程

  • 1 我們對(duì)一個(gè)類聲明了四個(gè)屬性name,_isName,isName_name看蚜,
@interface LGPerson : NSObject{
    @public
    NSString *_isName;
    NSString *name;
    NSString *isName;
    NSString *_name;

}
  • 2 在控制器中我們先實(shí)例化一個(gè)person對(duì)象,從而對(duì)調(diào)用KVC 進(jìn)行賦值過(guò)程赔桌;
 LGPerson *person = [[LGPerson alloc] init];
   // 1: KVC - 設(shè)置值的過(guò)程 setValue 分析調(diào)用過(guò)程
  [person setValue:@"LG_Cooci" forKey:@"name"]
  • 3 在person類中按先后順序執(zhí)行setter方法供炎,看看執(zhí)行的流程

第一步執(zhí)行setName方法

- (void)setName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

- (void)_setName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

- (void)setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}
- (void)_setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

打印結(jié)果

2020-10-28 16:36:11.503798+0800 002-KVC取值&賦值過(guò)程[8696:180841] -[LGPerson setName:] - LG_Cooci

第二步,注釋掉setName方法再次打印結(jié)果

//- (void)setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}
//
- (void)_setName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

- (void)setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}
- (void)_setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

打印結(jié)果

2020-10-28 16:41:37.143073+0800 002-KVC取值&賦值過(guò)程[8825:184607] -[LGPerson _setName:] - LG_Cooci

第三步注釋掉_setName再次打印

//- (void)setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}
//
//- (void)_setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}

- (void)setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

- (void)_setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

打印結(jié)果

2020-10-28 16:43:45.832732+0800 002-KVC取值&賦值過(guò)程[8883:186519] -[LGPerson setIsName:] - LG_Cooci

第四步疾党,注釋掉setIsName 再次打印結(jié)果

//- (void)setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}
//
//- (void)_setName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}

//- (void)setIsName:(NSString *)name{
//    NSLog(@"%s - %@",__func__,name);
//}

- (void)_setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

可以看到控制臺(tái)沒(méi)有任何打印結(jié)果碱茁,所以可以得出結(jié)論是- (void)_setIsName:(NSString *)name沒(méi)有調(diào)用。

結(jié)論仿贬,KVC的set方法調(diào)用順序?yàn)?setKey ->_setKey -> setIsKey

3.2 實(shí)例變量的賦值過(guò)程

通過(guò)以上的代碼驗(yàn)證纽竣,我們知道了實(shí)例變量的set方法調(diào)用流程;當(dāng)我們沒(méi)有相應(yīng)的set方法時(shí),我們?cè)俅慰纯聪鄳?yīng)的示例變量賦值過(guò)程蜓氨。

  • 1 我們所有的成員變量進(jìn)行監(jiān)控
  [person setValue:@"LG_Cooci" forKey:@"name"];
     NSLog(@"%@-%@-%@-%@",person->_name,person->_isName,person->name,person->isName);

打印結(jié)果

2020-10-28 16:51:28.428396+0800 002-KVC取值&賦值過(guò)程[9071:191676] LG_Cooci-(null)-(null)-(null)

  • 2 注釋掉_name 方法聋袋,再次打印
 NSString *_isName;
    NSString *name;
    NSString *isName;
   // NSString *_name;
 // 1: KVC - 設(shè)置值的過(guò)程 setValue 分析調(diào)用過(guò)程
     [person setValue:@"LG_Cooci" forKey:@"name"];
    
     NSLog(@"%@-%@-%@",person->_isName,person->name,person->isName);
    

打印結(jié)果

2020-10-28 16:57:00.847725+0800 002-KVC取值&賦值過(guò)程[9199:195725] LG_Cooci-(null)-(null)

  • 3 再次注釋掉_isName 再打印結(jié)果
 // NSString *_isName;
    NSString *name;
    NSString *isName;
   // NSString *_name;

[person setValue:@"LG_Cooci" forKey:@"name"];
NSLog(@"%@-%@",person->name,person->isName);

打印結(jié)果

2020-10-28 16:58:39.576608+0800 002-KVC取值&賦值過(guò)程[9254:197268] LG_Cooci-(null)

  • 4 再次注釋掉name 再次打印結(jié)果
// NSString *_isName;
   // NSString *name;
    NSString *isName;
   // NSString *_name;
[person setValue:@"LG_Cooci" forKey:@"name"];
NSLog(@"%@",person->isName);

打印結(jié)果

2020-10-28 17:00:24.788572+0800 002-KVC取值&賦值過(guò)程[9312:198897] LG_Cooci

結(jié)論:在沒(méi)有set方法的時(shí)候,KVC 對(duì)成員變量的賦值順序是 _key -> _isKey -> key ->isKey

四穴吹,valueForkey 取值的內(nèi)部原理

當(dāng)調(diào)用valueForKey:@”name“的代碼時(shí)幽勒,KVC對(duì)key的搜索方式不同于setValue:屬性值 forKey:@”name“,其搜索方式如下:


ValueForkey.png
  • 1 首先按get<Key>,<key>,is<Key>的順序方法查找getter方法港令,找到的話會(huì)直接調(diào)用啥容。如果是BOOL或者Int等值類型, 會(huì)將其包裝成一個(gè)NSNumber對(duì)象顷霹。
  • 2 如果上面的getter沒(méi)有找到咪惠,KVC則會(huì)查找countOf<Key>,objectIn<Key>AtIndex<Key>AtIndexes格式的方法。如果countOf<Key>方法和另外兩個(gè)方法中的一個(gè)被找到淋淀,那么就會(huì)返回一個(gè)可以響應(yīng)NSArray所有方法的代理集合(它是NSKeyValueArray遥昧,是NSArray的子類),調(diào)用這個(gè)代理集合的方法朵纷,或者說(shuō)給這個(gè)代理集合發(fā)送屬于NSArray的方法炭臭,就會(huì)以countOf<Key>,objectIn<Key>AtIndex<Key>AtIndexes這幾個(gè)方法組合的形式調(diào)用。還有一個(gè)可選的get<Key>:range:方法袍辞。所以你想重新定義KVC的一些功能鞋仍,你可以添加這些方法,需要注意的是你的方法名要符合KVC的標(biāo)準(zhǔn)命名方法搅吁,包括方法簽名凿试。
  • 3 如果上面的方法沒(méi)有找到,那么會(huì)同時(shí)查找countOf<Key>似芝,enumeratorOf<Key>,memberOf<Key>格式的方法那婉。如果這三個(gè)方法都找到,那么就返回一個(gè)可以響應(yīng)NSSet所的方法的代理集合党瓮,和上面一樣详炬,給這個(gè)代理集合發(fā)NSSet的消息,就會(huì)以countOf<Key>寞奸,enumeratorOf<Key>,memberOf<Key>組合的形式調(diào)用呛谜。
  • 4 如果還沒(méi)有找到,再檢查類方法+ (BOOL)accessInstanceVariablesDirectly,如果返回YES(默認(rèn)行為)枪萄,那么和先前的設(shè)值一樣隐岛,會(huì)按_<key>,_is<Key>,<key>,is<Key>的順序搜索成員變量名,這里不推薦這么做瓷翻,因?yàn)檫@樣直接訪問(wèn)實(shí)例變量破壞了封裝性聚凹,使代碼更脆弱割坠。如果重寫(xiě)了類方法+ (BOOL)accessInstanceVariablesDirectly返回NO的話,那么會(huì)直接調(diào)用valueForUndefinedKey:
  • 5 還沒(méi)有找到的話妒牙,調(diào)用valueForUndefinedKey:

4.1代碼驗(yàn)證KVC 的get方法順序

Person類中分別實(shí)現(xiàn)getName彼哼、name,isName_name方法

- (NSString *)getName{
    return NSStringFromSelector(_cmd);
}

- (NSString *)name{
    return NSStringFromSelector(_cmd);
}

- (NSString *)isName{
    return NSStringFromSelector(_cmd);
}

- (NSString *)_name{
    return NSStringFromSelector(_cmd);
}
  • 1 在控制器中對(duì)相關(guān)的屬性進(jìn)行取值內(nèi)容;
LGPerson *person = [[LGPerson alloc] init];
    
    // 1: KVC - 設(shè)置值的過(guò)程 setValue 分析調(diào)用過(guò)程
     [person setValue:@"LG_Cooci" forKey:@"name"];
    
    NSLog(@"取值:%@",[person valueForKey:@"name"]);

打印結(jié)果是

2020-10-28 17:10:39.770668+0800 002-KVC取值&賦值過(guò)程[9557:205906] 取值:getName

  • 2 注釋掉getName方法湘今,再次打印
//- (NSString *)getName{
//    return NSStringFromSelector(_cmd);
//}

- (NSString *)name{
    return NSStringFromSelector(_cmd);
}

- (NSString *)isName{
    return NSStringFromSelector(_cmd);
}

- (NSString *)_name{
    return NSStringFromSelector(_cmd);
}

打印結(jié)果

2020-10-28 17:11:43.928335+0800 002-KVC取值&賦值過(guò)程[9593:207045] 取值:name

  • 3 再次注釋掉name方法敢朱,打印
//- (NSString *)getName{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)name{
//    return NSStringFromSelector(_cmd);
//}

- (NSString *)isName{
    return NSStringFromSelector(_cmd);
}

- (NSString *)_name{
    return NSStringFromSelector(_cmd);
}

打印結(jié)果

2020-10-28 17:12:33.678782+0800 002-KVC取值&賦值過(guò)程[9622:208078] 取值:isName

  • 4 再注釋isName方法打印
//- (NSString *)getName{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)name{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)isName{
//    return NSStringFromSelector(_cmd);
//}

- (NSString *)_name{
    return NSStringFromSelector(_cmd);
}

打印結(jié)果

2020-10-28 17:13:29.096733+0800 002-KVC取值&賦值過(guò)程[9654:209106] 取值:_name

結(jié)論,KVC中相關(guān)成員變量的取值方法執(zhí)行順序是 getKey -> Key -> isKey -> _Key

4.2實(shí)例變量的取值過(guò)程

在沒(méi)有實(shí)現(xiàn)任何get方法的情況下摩瞎,

//- (NSString *)getName{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)name{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)isName{
//    return NSStringFromSelector(_cmd);
//}

//- (NSString *)_name{
//    return NSStringFromSelector(_cmd);
//}
  • 1 我們?cè)诳刂破髦袑?duì)所有的成員變量進(jìn)行一個(gè)賦值操作
person->_name = @"_name";
NSLog(@"取值:%@",[person valueForKey:@"name"]);

打印結(jié)果是

2020-10-28 17:25:02.021100+0800 002-KVC取值&賦值過(guò)程[9964:217084] 取值:_name

  • 2 注釋掉_name 再次打印結(jié)果
 NSString *_isName;
    NSString *name;
    NSString *isName;
    //NSString *_name;
person->_isName = @"_isName";
NSLog(@"取值:%@",[person valueForKey:@"name"]);

打印結(jié)果

2020-10-28 17:29:25.962006+0800 002-KVC取值&賦值過(guò)程[10103:221196] 取值:_isName

  • 3 再次注釋掉_isName 再次打印
//  NSString *_isName;
    NSString *name;
    NSString *isName;
    //NSString *_name;
 person->name = @"name";
  NSLog(@"取值:%@",[person valueForKey:@"name"]);

打印結(jié)果

2020-10-28 17:35:22.496774+0800 002-KVC取值&賦值過(guò)程[10281:225879] 取值:name

  • 4 再次注釋掉name 在打印結(jié)果
 //  NSString *_isName;
   // NSString *name;
    NSString *isName;
    //NSString *_name;
person->isName = @"isName";
NSLog(@"取值:%@",[person valueForKey:@"name"]);

打印結(jié)果是

2020-10-28 17:37:17.713126+0800 002-KVC取值&賦值過(guò)程[10352:227627] 取值:isName

結(jié)論拴签;成員變量的取值過(guò)程是 _Key -> _isKey -> Key ->isKey

八,總結(jié)

以上就是相關(guān)的KVC的原理旗们,通過(guò)以上的學(xué)習(xí)和總結(jié)蚓哩,了解了KVC 的賦值過(guò)程和取值過(guò)程的順序,執(zhí)行的流程已經(jīng)處理異常的步驟蚪拦,自己對(duì)KVC的理解更進(jìn)一步杖剪。有不足的地方希望各位大神多多指正冻押。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驰贷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子洛巢,更是在濱河造成了極大的恐慌括袒,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稿茉,死亡現(xiàn)場(chǎng)離奇詭異锹锰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)漓库,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門恃慧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人渺蒿,你說(shuō)我怎么就攤上這事痢士。” “怎么了茂装?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵怠蹂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我少态,道長(zhǎng)城侧,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任彼妻,我火速辦了婚禮嫌佑,結(jié)果婚禮上豆茫,老公的妹妹穿的比我還像新娘。我一直安慰自己歧强,他們只是感情好澜薄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著摊册,像睡著了一般肤京。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茅特,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天忘分,我揣著相機(jī)與錄音,去河邊找鬼白修。 笑死妒峦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兵睛。 我是一名探鬼主播肯骇,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼祖很!你這毒婦竟也來(lái)了笛丙?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤假颇,失蹤者是張志新(化名)和其女友劉穎胚鸯,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體笨鸡,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姜钳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了形耗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哥桥。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖激涤,靈堂內(nèi)的尸體忽然破棺而出拟糕,到底是詐尸還是另有隱情,我是刑警寧澤昔期,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布已卸,位于F島的核電站,受9級(jí)特大地震影響硼一,放射性物質(zhì)發(fā)生泄漏累澡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一般贼、第九天 我趴在偏房一處隱蔽的房頂上張望愧哟。 院中可真熱鬧奥吩,春花似錦、人聲如沸蕊梧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)肥矢。三九已至端衰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甘改,已是汗流浹背旅东。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留十艾,地道東北人抵代。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像忘嫉,于是被迫代替她去往敵國(guó)和親荤牍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345