(轉(zhuǎn))KVC, KVO實(shí)現(xiàn)原理剖析

作者:wangzz
原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431

前言:
1墓造、本文基本不講KVC/KVO的用法紊册,只結(jié)合網(wǎng)上的資料說說對這種技術(shù)的理解。
2、由于KVO內(nèi)容較少吮廉,而且是以KVC為基礎(chǔ)實(shí)現(xiàn)的盅称,本文將著重介紹KVC部分蜗顽。
一萍膛、簡介
KVC/KVO是觀察者模式的一種實(shí)現(xiàn),在Cocoa中是以被萬物之源NSObject類實(shí)現(xiàn)的NSKeyValueCoding/NSKeyValueObserving非正式協(xié)議的形式被定義為基礎(chǔ)框架的一部分擅羞。從協(xié)議的角度來說尸变,KVC/KVO本質(zhì)上是定義了一套讓我們?nèi)プ袷睾蛯?shí)現(xiàn)的方法。
當(dāng)然减俏,KVC/KVO實(shí)現(xiàn)的根本是Objective-C的動態(tài)性和runtime召烂,這在后文的原理部分會有詳述。
另外娃承,KVC/KVO機(jī)制離不開訪問器方法的實(shí)現(xiàn)奏夫,這在后文中也有解釋。
1草慧、KVC簡介
全稱是Key-value coding桶蛔,翻譯成鍵值編碼匙头。顧名思義漫谷,在某種程度上跟map的關(guān)系匪淺。它提供了一種使用字符串而不是訪問器方法去訪問一個對象實(shí)例變量的機(jī)制蹂析。
2舔示、KVO簡介
全稱是Key-value observing碟婆,翻譯成鍵值觀察。提供了一種當(dāng)其它對象屬性被修改的時候能通知當(dāng)前對象的機(jī)制惕稻。再M(fèi)VC大行其道的Cocoa中竖共,KVO機(jī)制很適合實(shí)現(xiàn)model和controller類之間的通訊。
二俺祠、KVC相關(guān)技術(shù)
1公给、Key和Key Path
KVC定義了一種按名稱訪問對象屬性的機(jī)制,支持這種訪問的主要方法是:
[java] view plain copy

  • (id)valueForKey:(NSString *)key;
  • (void)setValue:(id)value forKey:(NSString *)key;
  • (id)valueForKeyPath:(NSString *)keyPath;
  • (void)setValue:(id)value forKeyPath:(NSString *)keyPath;

前邊兩個方法用到的Key較容易理解蜘渣,就是要訪問的屬性名稱對應(yīng)的字符串淌铐。
后面兩個方法用到的KeyPath是一個被點(diǎn)操作符隔開的用于訪問對象的指定屬性的字符串序列。比如KeyPath address.street將會訪問消息接收對象所包含的address屬性中包含的一個street屬性蔫缸。其實(shí)KeyPath說白了就是我們平時使用點(diǎn)操作訪問某個對象的屬性時所寫的那個字符串腿准。
2、點(diǎn)語法和KVC
在實(shí)現(xiàn)了訪問器方法的類中拾碌,使用點(diǎn)語法和KVC訪問對象其實(shí)差別不大吐葱,二者可以任意混用。但是沒有訪問起方法的類中校翔,點(diǎn)語法無法使用弟跑,這時KVC就有優(yōu)勢了。(原因見第三部分的第一節(jié):KVC如何訪問屬性值防症。)
3窖认、一對多關(guān)系(To-Many)中的集合訪問器方法
我們平時大部分使用的屬性都是一對一關(guān)系(To-One),比如Person類中的name屬性,每個人只有一個名字告希。但也有一對多的關(guān)系扑浸,比如Person中有一個friendsName屬性,這是個集合(在Objective-C中可以是NSArray燕偶,NSSet等)喝噪,保存的是一個人的所有朋友的名字。
當(dāng)操作一對多的屬性中的內(nèi)容時指么,我們有兩種選擇:
①間接操作
先通過KVC方法取到集合屬性酝惧,然后通過集合屬性操作集合中的元素。
②直接操作
蘋果為我們提供了一些方法模板伯诬,我們可以以規(guī)定的格式實(shí)現(xiàn)這些方法來達(dá)到訪問集合屬性中元素的目的晚唇。
有序集合對應(yīng)方法如下:
[java] view plain copy

-countOf<Key>
//必須實(shí)現(xiàn),對應(yīng)于NSArray的基本方法count:
-objectIn<Key>AtIndex:
-<key>AtIndexes:
//這兩個必須實(shí)現(xiàn)一個盗似,對應(yīng)于 NSArray 的方法 objectAtIndex: 和 objectsAtIndexes:
-get<Key>:range:
//不是必須實(shí)現(xiàn)的哩陕,但實(shí)現(xiàn)后可以提高性能,其對應(yīng)于 NSArray 方法 getObjects:range:

-insertObject:in<Key>AtIndex:
-insert<Key>:atIndexes:
//兩個必須實(shí)現(xiàn)一個,類似于 NSMutableArray 的方法 insertObject:atIndex: 和 insertObjects:atIndexes:
-removeObjectFrom<Key>AtIndex:
-remove<Key>AtIndexes:
//兩個必須實(shí)現(xiàn)一個悍及,類似于 NSMutableArray 的方法 removeObjectAtIndex: 和 removeObjectsAtIndexes:
-replaceObjectIn<Key>AtIndex:withObject:
-replace<Key>AtIndexes:with<Key>:
//可選的闽瓢,如果在此類操作上有性能問題,就需要考慮實(shí)現(xiàn)之

無序集合對應(yīng)方法如下:
[java] view plain copy

-countOf<Key>
//必須實(shí)現(xiàn)心赶,對應(yīng)于NSArray的基本方法count:
-objectIn<Key>AtIndex:
-<key>AtIndexes:
//這兩個必須實(shí)現(xiàn)一個扣讼,對應(yīng)于 NSArray 的方法 objectAtIndex: 和 objectsAtIndexes:
-get<Key>:range:
//不是必須實(shí)現(xiàn)的,但實(shí)現(xiàn)后可以提高性能缨叫,其對應(yīng)于 NSArray 方法 getObjects:range:

-insertObject:in<Key>AtIndex:
-insert<Key>:atIndexes:
//兩個必須實(shí)現(xiàn)一個椭符,類似于 NSMutableArray 的方法 insertObject:atIndex: 和 insertObjects:atIndexes:
-removeObjectFrom<Key>AtIndex:
-remove<Key>AtIndexes:
//兩個必須實(shí)現(xiàn)一個,類似于 NSMutableArray 的方法 removeObjectAtIndex: 和 removeObjectsAtIndexes:
-replaceObjectIn<Key>AtIndex:withObject:
-replace<Key>AtIndexes:with<Key>:
//這兩個都是可選的耻姥,如果在此類操作上有性能問題艰山,就需要考慮實(shí)現(xiàn)之

不過這些方法除非是很有需求,否則個人認(rèn)為沒有實(shí)現(xiàn)的必要咏闪,間接法也不是很麻煩曙搬,基本能滿足需求了。值得指出的是鸽嫂,蘋果甚至都沒有讓這些方法以哪怕是非正式協(xié)議的形式出現(xiàn)纵装,而只是在編程指南中提了一下。
4据某、鍵值驗(yàn)證(Key-Value Validation)
KVC提供了驗(yàn)證Key對應(yīng)的Value是否可用的方法:
[java] view plain copy

  • (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;

該方法默認(rèn)的實(shí)現(xiàn)是調(diào)用一個如下格式的方法:
[java] view plain copy

  • (BOOL)validate<Key>:error:

比如屬性name對應(yīng)的方法為:
[java] view plain copy

-(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError {
// Implementation specific code.
return ...;
}

這樣就給了我們一次糾錯的機(jī)會橡娄。
需要指出的是,KVC是不會自動調(diào)用鍵值驗(yàn)證方法的癣籽,就是說我們需要手動驗(yàn)證挽唉。但是有些技術(shù),比如CoreData會自動調(diào)用筷狼。
5瓶籽、KVC對數(shù)值和結(jié)構(gòu)體型屬性的支持
一套機(jī)制如果不支持?jǐn)?shù)值和結(jié)構(gòu)體型的數(shù)據(jù),那么它的實(shí)用性就會大大折扣埂材。幸運(yùn)的是KVC中蘋果對這方面的支持做的很好塑顺。KVC可以自動的將數(shù)值或結(jié)構(gòu)體型的數(shù)據(jù)打包或解包成NSNumber或NSValue對象,以達(dá)到適配的目的俏险。
舉個例子严拒,Person類有個個NSInteger類型的age屬性
①修改值
我們通過KVC技術(shù)使用如下方式設(shè)置age屬性的值:
[java] view plain copy

[person setValue:[NSNumber numberWithInteger:5] forKey:@"age"];

我們賦給age的是一個NSNumber對象,KVC會自動的將NSNumber對象轉(zhuǎn)換成NSInteger對象竖独,然后再調(diào)用相應(yīng)的訪問器方法設(shè)置age的值裤唠。
②獲取值
同樣,以如下方式獲取age屬性值:
[java] view plain copy

[person valueForKey:@"age"];

這時莹痢,會以NSNumber的形式返回age的值种蘸。
需要說明的是墓赴,什么時候返回的是NSNumber,什么時候返回的是NSValue劈彪?
③使用NSNumber封裝
可以使用NSNumber的數(shù)據(jù)類型有:
[java] view plain copy

  • (NSNumber *)numberWithChar:(char)value;
  • (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
  • (NSNumber *)numberWithShort:(short)value;
  • (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
  • (NSNumber *)numberWithInt:(int)value;
  • (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
  • (NSNumber *)numberWithLong:(long)value;
  • (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
  • (NSNumber *)numberWithLongLong:(long long)value;
  • (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
  • (NSNumber *)numberWithFloat:(float)value;
  • (NSNumber *)numberWithDouble:(double)value;
  • (NSNumber *)numberWithBool:(BOOL)value;
  • (NSNumber *)numberWithInteger:(NSInteger)value NS_AVAILABLE(10_5, 2_0);
  • (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value NS_AVAILABLE(10_5, 2_0);

總之就是一些常見的數(shù)值型數(shù)據(jù)竣蹦。
④使用NSValue封裝
NSValue主要用于處理結(jié)構(gòu)體型的數(shù)據(jù)顶猜,它本身提供了如下集中結(jié)構(gòu)的支持:
[java] view plain copy

  • (NSValue *)valueWithCGPoint:(CGPoint)point;
  • (NSValue *)valueWithCGSize:(CGSize)size;
  • (NSValue *)valueWithCGRect:(CGRect)rect;
  • (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform;
  • (NSValue *)valueWithUIEdgeInsets:(UIEdgeInsets)insets;
  • (NSValue *)valueWithUIOffset:(UIOffset)insets NS_AVAILABLE_IOS(5_0);

只有有限的6種而已沧奴!那對于其它自定義的結(jié)構(gòu)體怎么辦?別擔(dān)心长窄,任何結(jié)構(gòu)體都是可以轉(zhuǎn)化成NSValue對象的滔吠,具體實(shí)現(xiàn)方法參見我之前的一篇文章:
http://blog.csdn.net/wzzvictory/article/details/8614433
6、集合運(yùn)算符(Collection Operators)
集合運(yùn)算符是一個特殊的Key Path挠日,可以作為參數(shù)傳遞給valueForKeyPath:方法疮绷,注意只能是這個方法,如果傳給了valueForKey:方法保證你程序崩潰嚣潜。
運(yùn)算符是一個以@開頭的特殊字符串冬骚,格式如下圖所示:


①簡單集合運(yùn)算符
簡單集合運(yùn)算符共有@avg,@count懂算,@max只冻,@min,@sum5種计技,都表示啥不用我說了吧喜德,目前還不支持自定義。
有一個集合類的對象:transactions垮媒,它存儲了一個個的Transaction類的實(shí)例舍悯,該類有三個屬性:payee,amount睡雇,date萌衬。下面以此為例說明如何使用這些運(yùn)算符:
要獲取amount的平均值可以這樣:
[java] view plain copy

NSNumber *transactionAverage = [transactions valueForKeyPath:@"@avg.amount"];

要獲取transactions集合中元素數(shù)目可以這樣:
[java] view plain copy

NSNumber *numberOfTransactions = [transactions valueForKeyPath:@"@count"];

需要之處的是,@count是這些集合運(yùn)算符中比較特殊的一個它抱,因?yàn)樗鼪]有右路經(jīng)奄薇,原因很容易理解。
②對象運(yùn)算符
比集合運(yùn)算符稍微復(fù)雜抗愁,能以數(shù)組的方式返回指定的內(nèi)容馁蒂,一共有兩種:
[java] view plain copy

@distinctUnionOfObjects
@unionOfObjects

它們的返回值都是NSArray,區(qū)別是前者返回的元素都是唯一的蜘腌,是去重以后的結(jié)果沫屡;后者返回的元素是全集。
用法如下:
[java] view plain copy

NSArray *payees = [transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"];
NSArray *payees = [transactions valueForKeyPath:@"@unionOfObjects.payee"];

前者會將收款人的姓名去除重復(fù)的以后返回撮珠,后者直接返回所有收款人的姓名沮脖。
③Array和Set操作符
這種情況更復(fù)雜了金矛,說的是集合中包含集合的情況,我們執(zhí)行了如下的一段代碼:
[java] view plain copy

// Create the array that contains additional arrays.
self.arrayOfTransactionsArray = [NSMutableArray array];

// Add the array of objects used in the above examples.
[arrayOfTransactionsArray addObject:transactions];

// Add a second array of objects; this array contains alternate values.
[arrayOfTransactionsArrays addObject:moreTransactions];

得到了一個包含集合的集合:arrayOfTransactionsArray
這時如果我們想操作arrayOfTransactionsArray中包含的集合中的元素時勺届,可以使用如下三個運(yùn)算符:
[java] view plain copy

@distinctUnionOfArrays
@unionOfArrays
@distinctUnionOfSets

前兩個針對的集合是Arrays驶俊,后一個針對的集合是Sets。因?yàn)镾ets中的元素本身就是唯一的免姿,所以沒有對應(yīng)的@unionOfSets運(yùn)算符饼酿。

它們的用法舉例如下:
[java] view plain copy

NSArray *payees = [arrayOfTransactionsArrays valueForKeyPath:@"@unionOfArrays.payee"];

三、實(shí)現(xiàn)原理
1胚膊、KVC如何訪問屬性值
KVC再某種程度上提供了訪問器的替代方案故俐。不過訪問器方法是一個很好的東西,以至于只要是有可能紊婉,KVC也盡量再訪問器方法的幫助下工作药版。為了設(shè)置或者返回對象屬性,KVC按順序使用如下技術(shù):
①檢查是否存在-<key>喻犁、-is<key>(只針對布爾值有效)或者-get<key>的訪問器方法槽片,如果有可能,就是用這些方法返回值肢础;
檢查是否存在名為-set<key>:的方法还栓,并使用它做設(shè)置值。對于-get<key>和-set<key>:方法乔妈,將大寫Key字符串的第一個字母蝙云,并與Cocoa的方法命名保持一致;
②如果上述方法不可用路召,則檢查名為-_<key>勃刨、-_is<key>(只針對布爾值有效)、-_get<key>和-set<key>:方法股淡;
③如果沒有找到訪問器方法身隐,可以嘗試直接訪問實(shí)例變量。實(shí)例變量可以是名為:<key>或
<key>;
④如果仍為找到唯灵,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法贾铝。這些方法的默認(rèn)實(shí)現(xiàn)都是拋出異常,我們可以根據(jù)需要重寫它們埠帕。
2垢揩、KVC/KVO實(shí)現(xiàn)原理
鍵值編碼和鍵值觀察是根據(jù)isa-swizzling技術(shù)來實(shí)現(xiàn)的,主要依據(jù)runtime的強(qiáng)大動態(tài)能力敛瓷。下面的這段話是引自網(wǎng)上的一篇文章:
http://blog.csdn.net/kesalin/article/details/8194240
當(dāng)某個類的對象第一次被觀察時叁巨,系統(tǒng)就會在運(yùn)行期動態(tài)地創(chuàng)建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的 setter 方法呐籽。派生類在被重寫的 setter 方法實(shí)現(xiàn)真正的通知機(jī)制锋勺,就如前面手動實(shí)現(xiàn)鍵值觀察那樣蚀瘸。這么做是基于設(shè)置屬性會調(diào)用 setter 方法,而通過重寫就獲得了 KVO 需要的通知機(jī)制庶橱。當(dāng)然前提是要通過遵循 KVO 的屬性設(shè)置方式來變更屬性值贮勃,如果僅是直接修改屬性對應(yīng)的成員變量,是無法實(shí)現(xiàn) KVO 的苏章。同時派生類還重寫了 class 方法以“欺騙”外部調(diào)用者它就是起初的那個類寂嘉。然后系統(tǒng)將這個對象的 isa 指針指向這個新誕生的派生類,因此這個對象就成為該派生類的對象了布近,因而在該對象上對 setter 的調(diào)用就會調(diào)用重寫的 setter垫释,從而激活鍵值通知機(jī)制丝格。此外撑瞧,派生類還重寫了 dealloc 方法來釋放資源。
原文寫的很好显蝌,還舉了解釋性的例子预伺,大家可以去看看。
在我之前的一篇介紹Objective-C類和元類的文章:
http://blog.csdn.net/wzzvictory/article/details/8592492
中介紹過曼尊,isa指針指向的其實(shí)是類的元類酬诀,如果之前的類名為:Person,那么被runtime更改以后的類名會變成:NSKVONotifying_Person骆撇。
新的NSKVONotifying_Person類會重寫以下方法:
增加了監(jiān)聽的屬性對應(yīng)的set方法瞒御,class,dealloc神郊,_isKVOA肴裙。
①class
重寫class方法是為了我們調(diào)用它的時候返回跟重寫繼承類之前同樣的內(nèi)容。
打印如下內(nèi)容:
[java] view plain copy

NSLog(@"self->isa:%@",self->isa);
NSLog(@"self class:%@",[self class]);

在建立KVO監(jiān)聽前涌乳,打印結(jié)果為:
[java] view plain copy

self->isa:Person
self class:Person

在建立KVO監(jiān)聽之后蜻懦,打印結(jié)果為:
[java] view plain copy

self->isa:NSKVONotifying_Person
self class:Person

這也是isa指針和class方法的一個區(qū)別,大家使用的時候注意夕晓。
②重寫set方法
新類會重寫對應(yīng)的set方法宛乃,是為了在set方法中增加另外兩個方法的調(diào)用:
[java] view plain copy

  • (void)willChangeValueForKey:(NSString *)key
  • (void)didChangeValueForKey:(NSString *)key

其中,didChangeValueForKey:方法負(fù)責(zé)調(diào)用:
[java] view plain copy

  • (void)observeValueForKeyPath:(NSString *)keyPath
    ofObject:(id)object
    change:(NSDictionary *)change
    context:(void *)context

方法蒸辆,這就是KVO實(shí)現(xiàn)的原理了征炼!
如果沒有任何的訪問器方法,-setValue:forKey方法會直接調(diào)用:
[java] view plain copy

  • (void)willChangeValueForKey:(NSString *)key
  • (void)didChangeValueForKey:(NSString *)key

如果在沒有使用鍵值編碼且沒有使用適當(dāng)命名的訪問起方法的時候躬贡,我們只需要顯示調(diào)用上述兩個方法谆奥,同樣可以使用KVO!
總結(jié)一下逗宜,想使用KVO有三種方法:
1)使用了KVC
使用了KVC雄右,如果有訪問器方法空骚,則運(yùn)行時會在訪問器方法中調(diào)用will/didChangeValueForKey:方法;
沒用訪問器方法擂仍,運(yùn)行時會在setValue:forKey方法中調(diào)用will/didChangeValueForKey:方法囤屹。
2)有訪問器方法
運(yùn)行時會重寫訪問器方法調(diào)用will/didChangeValueForKey:方法。
因此逢渔,直接調(diào)用訪問器方法改變屬性值時肋坚,KVO也能監(jiān)聽到。
3)顯示調(diào)用will/didChangeValueForKey:方法肃廓。
總之智厌,想使用KVO,只要有will/didChangeValueForKey:方法就可以了盲赊。
③_isKVOA
這個私有方法估計(jì)是用來標(biāo)示該類是一個 KVO 機(jī)制聲稱的類铣鹏。
四、優(yōu)點(diǎn)和缺點(diǎn)
1哀蘑、優(yōu)點(diǎn)
①可以再很大程度上簡化代碼
例子網(wǎng)上很多诚卸,這就不舉了
②能跟腳本語言很好的配合
才疏學(xué)淺,沒學(xué)過AppleScript等腳本語言绘迁,所以沒能深刻體會到該優(yōu)點(diǎn)合溺。
2、缺點(diǎn)
KVC的缺點(diǎn)不明顯缀台,主要是KVO的棠赛,詳情可以參考這篇文章:
http://www.mikeash.com/pyblog/key-value-observing-done-right.html
核心思想是說KVO的回調(diào)機(jī)制,不能傳一個selector或者block作為回調(diào)膛腐,而必須重寫-addObserver:forKeyPath:options:context:方法所引發(fā)的一系列問題睛约。問了解決這個問題,作者還親自實(shí)現(xiàn)了一個MAKVONotificationCenter類依疼,代碼見github:
https://github.com/mikeash/MAKVONotificationCenter
不過個人認(rèn)為這只是蘋果做的KVO不夠完美痰腮,不能算是缺陷。

參考文檔:
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/KeyValueCoding.html#//apple_ref/doc/uid/10000107-SW1
http://blog.csdn.net/kesalin/article/details/8194240

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末律罢,一起剝皮案震驚了整個濱河市膀值,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌误辑,老刑警劉巖沧踏,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巾钉,居然都是意外死亡翘狱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門砰苍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來潦匈,“玉大人阱高,你說我怎么就攤上這事〔缢酰” “怎么了赤惊?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凰锡。 經(jīng)常有香客問我未舟,道長,這世上最難降的妖魔是什么掂为? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任裕膀,我火速辦了婚禮,結(jié)果婚禮上勇哗,老公的妹妹穿的比我還像新娘昼扛。我一直安慰自己,他們只是感情好智绸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布野揪。 她就那樣靜靜地躺著访忿,像睡著了一般瞧栗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上海铆,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天迹恐,我揣著相機(jī)與錄音,去河邊找鬼卧斟。 笑死殴边,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的珍语。 我是一名探鬼主播锤岸,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼板乙!你這毒婦竟也來了是偷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤募逞,失蹤者是張志新(化名)和其女友劉穎蛋铆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體放接,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刺啦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纠脾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玛瘸。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜕青,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糊渊,到底是詐尸還是另有隱情市咆,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布再来,位于F島的核電站蒙兰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏芒篷。R本人自食惡果不足惜搜变,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望针炉。 院中可真熱鬧挠他,春花似錦、人聲如沸篡帕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镰烧。三九已至拢军,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怔鳖,已是汗流浹背茉唉。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留结执,地道東北人度陆。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像献幔,于是被迫代替她去往敵國和親懂傀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

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

  • KVC(Key-value coding)鍵值編碼蜡感,單看這個名字可能不太好理解蹬蚁。其實(shí)翻譯一下就很簡單了,就是指iO...
    朽木自雕也閱讀 1,560評論 6 1
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,146評論 30 470
  • KVC/KVO 概念 KVC : 即 Key-Value-Coding铸敏,用于鍵值編碼缚忧。作為 cocoa 的一個標(biāo)準(zhǔn)...
    滿臉胡茬的小碼農(nóng)閱讀 1,957評論 2 8
  • 夜,深杈笔; 心闪水,靜。 姨夫帶來了新鮮的大螃蟹,自己出海打撈球榆,開車帶回來的朽肥,不吃海鮮的我,也品嘗了一只~ 家里多了兩口...
    靜默如謎l閱讀 390評論 0 0
  • 兒子昨天晚上磕掉了一顆門牙持钉。 媽媽在衛(wèi)生間洗澡衡招,兒子在屋里玩玩具,突然聽到一陣哭喊每强。媽媽進(jìn)門一看始腾,兒子雙手撐在地上...
    追光小強(qiáng)閱讀 221評論 3 2