高效的OC代碼

前言

? ? 要啥前言超埋,直接就是擼搏讶。


1、OC與C

? ? ? OC是C的超集霍殴,所有C語言的特性媒惕,在OC上都可以使用。同時掌握這兩門語言来庭,對于提升OC的代碼效率非常重要妒蔚。尤其是理解C語言的內(nèi)存模型,有助于理解OC的“引用計數(shù)”機制的工作原理月弛,不過現(xiàn)在ARC已經(jīng)很普遍了肴盏,很多剛上道的OCer 基本不太理解引用計數(shù),根本不用嘛帽衙。Swift的出現(xiàn)更加讓OC尷尬菜皂,總而言之废麻,還是看自己的理解吧戒祠。OC使用動態(tài)綁定的消息結(jié)構(gòu)滩字,也就是說只有在運行時,才會檢查對象蚁堤,收到消息,執(zhí)行哪段代碼由運行期決定而非編譯器杖虾。這點與JAVA完全不同条辟。


2、頭文件引入

? ? 這個是老梗了胳施,相信老的OCer都應該了解溯祸。我再復述一遍吧。

? ? 當在a.h頭文件中需要用到b類文件時舞肆,偷懶的童鞋會直接#import "b.h"焦辅,這樣做就有可能引起某些問題了。

編譯時間增加椿胯,當編譯a文件的時候筷登,會將b文件全部編譯。其實在編譯a時不需要知道b文件的全部細節(jié)哩盲,只要知道一個類名就好前方。?

避免頭文件的循環(huán)引用,當a的頭文件#import "b.h",同時在b的頭文件#import "a.h"廉油,這樣就產(chǎn)生了兩個類的循環(huán)引用惠险,當然使用#import 而非#include指令不會導致死循環(huán),但卻意味著兩個類里有一個無法正確編譯抒线。

? ? 針對以上兩個問題班巩,產(chǎn)生了一個名詞“向前聲明”。即通過在a的頭文件中使用@class b嘶炭;就可以在a文件中使用b類抱慌。在a.m文件中再#import "b.h"。這樣就可以減少編譯的時間眨猎,也可以防止了頭文件的循環(huán)引用抑进。

? ? 還有一種情況需要在頭文件中,必須要#import睡陪,即a類繼承自b類或者遵循某類協(xié)議单匣,那么該類需要完整定義,且不能使用向前聲明宝穗。根據(jù)這種情況户秤,可以考慮將某些代碼放入分類(class continuation)中,比如是否遵循某個協(xié)議(或者講協(xié)議的定義放入單獨的頭文件)


3逮矛、多用字面量語法鸡号,少用與之等價的方法

? ?寫OC時,經(jīng)常會用到幾個類须鼎,他們屬于Foundation鲸伴,NSString府蔗、NSNumber、NSArray汞窗、NSDictionary姓赤,針對這幾個類,推薦多用字面量語法進行定義仲吏,減少alloc不铆,init方式初始化。例如

NSString *demoString = @"Demo";

NSNumber *two??????? = @2;

NSArray? *cityArray? = @[@"北京",@"天津"];

NSDictionary *cityDic= @{@"name":@"北京",@"code":@"010"};


NSString *capital??? = cityArray[0];

NSString *capitalName= cityDic[@"name"];

字面量語法實際上是一種“語法糖”裹唆,可另程序更易讀誓斥,減少出錯率。但也有他的局限性许帐。在用NSArray時劳坑,需要先確保值中沒有nil,如果有成畦,則會拋出異常距芬。


4、多用類型變量循帐,少用#define預處理

? ?定義一個動畫執(zhí)行時間為0.3秒框仔,也許有人會這么做:

#define ANIMATION_DURATION 0.3

? 這么寫首先沒有定義出這個常量的類型,duration應該是時間惧浴,但是沒有明確指出。另外如果其他類引用了這個類奕剃,那么所有的ANIMATION_DURATION都會替換成了0.3衷旅,有可能會產(chǎn)生小問題。

? 解決這個問題可以定義一個類型為NSTimeInterval的常量:




static const NSTimeInterval kAnimationDuration 0.3


?這樣可以更清晰標明這個屬性的類型纵朋,也容易讓其他人明白其作用柿顶。需要注意的是命名規(guī)范,弱常量局限于實現(xiàn)文件之內(nèi)操软,則在前面加字幕k嘁锯,如果供外部類使用,需要加類名前綴聂薪。




5家乘、用枚舉表示狀態(tài)、選項藏澳、狀態(tài)碼


? 每一個狀態(tài)都用一個便于理解的值來表示仁锯,寫出來的代碼更容易理解。


? 專門說一下翔悠,如果選項是可組合的业崖,更需要用枚舉了野芒。各選項之間通過“按位或操作符”來組合,使用方式如下:


typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {

????UIViewAutoresizingNone???????????????? = 0,

????UIViewAutoresizingFlexibleLeftMargin?? = 1 << 0,

????UIViewAutoresizingFlexibleWidth??????? = 1 << 1,

????UIViewAutoresizingFlexibleRightMargin? = 1 << 2,

????UIViewAutoresizingFlexibleTopMargin??? = 1 << 3,

????UIViewAutoresizingFlexibleHeight?????? = 1 << 4,

????UIViewAutoresizingFlexibleBottomMargin = 1 << 5

};


? 這樣双炕,每個選項都可以啟用或禁用狞悲,在做判斷的時候,用“按位與運算符”判斷是否啟用:


enum UIViewAutoresizing resize = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

if (resize & UIViewAutoresizingFlexibleHeight) {

????//處理height

}


?6妇斤、理解屬性的概念

? ?屬性特質(zhì)

原子性:如果屬性具有nonatomic摇锋,標明屬性不使用同步鎖,未聲明atomic趟济,標明屬性是原子的乱投。區(qū)別在于atomic特質(zhì)的獲取方法會通過鎖定機制確保其操作的原子性,即多個線程讀同一屬性顷编,無論何時總能看到有效值戚炫。如果不加鎖的情況,當某一線程正在改寫值時媳纬,另外一個線程把未修改的屬性值取出來双肤,結(jié)果可能不對。iOS的同步鎖開銷較大會帶來性能問題钮惠,盡量少用茅糜。

? ? ? ? 讀寫權(quán)限:具有readwrite權(quán)限的屬性擁有g(shù)etter和setter方法,如果該屬性由@synthesize實現(xiàn)素挽,則編譯器會自動生成這兩個方法蔑赘。

? ? ? ? ? ? ? ? ? ? ? ? ? 具有readonly權(quán)限的屬性只擁有g(shù)etter方法,

? ? ? ? 內(nèi)存管理語義:

? ? ? ? ? ? ? ? ? ? ? ? ?assign:“設置方法”只會針對“純量類型”的簡單賦值操作预明。

? ? ? ? ? ? ? ? ? ? ? ? ?strong:此特質(zhì)表明屬性定義了一種“擁有關系”缩赛,為這種屬性設置新值時,會先保留新值撰糠,并釋放舊值酥馍,然后再將新值賦值上去。

? ? ? ? ? ? ? ? ? ? ? ? ?weak : 此特質(zhì)表明屬性定義了一種“非擁有關系”阅酪,為這種屬性設置新值時旨袒,既不保留新值,也不釋放舊值术辐,同assign類似砚尽,然而在屬性所指的對象被銷毀時,屬性值也會清空

? ? ? ? ? ? ? ? ? ? ? ? ?unsafe_unretained: 此特質(zhì)和assign相同辉词,但是只適用于對象類型尉辑,表達一種“非擁有關系”,當目標對象被銷毀時较屿,屬性值不會被清空隧魄,同weak不同卓练。

? ? ? ? ? ? ? ? ? ? ? ? copy: 此特質(zhì)與strong類似,然而設置方法并不保留新值购啄,而是將其copy襟企,當屬性為NSString類型時,經(jīng)常用此特質(zhì)狮含,保護其封裝性顽悼。因為傳遞的值很可能是NSMutableString,即NSString的子類几迄,若是不拷貝字符串蔚龙,那么設置完后,可能會在不知情的情況下遭人篡改映胁,所以這時就要拷貝一份“不可變的”字符串木羹。

? ? ? ? 方法名:getter = 指定獲取方法的名稱,如果某屬性是BOOL類型解孙,你想為其getter方法添加is前綴坑填,就可以通過這個指定。

? ? ? ? ? ? ? ? ? ? ? setter = 指定設置屬性的名稱弛姜,不常用脐瑰。


7、對象內(nèi)部盡量直接訪問實例變量

? ? 屬性訪問和直接訪問的區(qū)別:

直接訪問不需要經(jīng)過OC的方法派發(fā)廷臼,所以訪問實例變量的速度比較快

直接訪問不會調(diào)用“設置方法”苍在,會繞過屬性定義的內(nèi)存管理語義,比如一個屬性定義為copy荠商,如果直接訪問寂恬,并不會拷貝屬性,而是保留新值结啼,釋放舊值掠剑。

如果直接訪問實例變量屈芜,不會觸發(fā)KVO郊愧。

通過屬性訪問有助于排查與之相關的錯誤。


8井佑、理解“對象等同性”的概念

? ? 提到“等同性”属铁,可能第一個想法就是"==",但是"=="比較出來的結(jié)果未必是我們想要的結(jié)果躬翁,因為他比較的是兩個指針本身焦蘑,而不是所指的對象。一般來說盒发,兩個不同類型的對象總是不相等的例嘱,如果已經(jīng)知道兩個受測對象是相同的狡逢,那么可以看下如下代碼:

NSString *foo = @"ZRC123";

NSString *foo1 = [NSString stringWithFormat:@"ZRC %@",@"123"];

BOOL equalA = foo == foo1; //equalA = NO

BOOL equalB = [foo isEqual:foo1]; // equalB = YES

BOOL equalC = [foo isEqualToString:foo1]; //equalC = YES


? ? 從上述代碼不難看出“==”與“isEqual”之間的區(qū)別,NSString實現(xiàn)了自己獨有的等同性判斷方法拼卵,名叫"isEqualToString"奢浑,傳遞的參數(shù)必須是NSString,否則為undefined腋腮。該方法要比“isEqual”快雀彼,后者要執(zhí)行其他方法。

? ? NSObject協(xié)議中有兩個用于判斷等同性的關鍵方法:

? ? -(BOOL)isEqual:(id)object;

? ? -(NSUInteger)hash;

? ?如果“isEqual”判定兩個對象相同即寡,則hash值返回的值必定相同徊哑,但如果hash值返回相同,那么“isEqual”未必會認為兩個對象相同聪富。

? ?如果經(jīng)常需要判斷等同性莺丑,很可能需要自己去實現(xiàn)一個判斷方法,無需檢測參數(shù)類型善涨,可以大大提升檢測速度窒盐。在編寫判定方法時,也應一并復寫“isEqual”方法钢拧。常用的復寫“isEqual”蟹漓,是判斷受測參數(shù)與接受該消息的參數(shù)是否屬于同類,如果屬于源内,調(diào)用自己編寫的判定方法葡粒,如果不同,則調(diào)用超類膜钓。

等同性執(zhí)行深度

? ?創(chuàng)建等同性判斷方法時嗽交,需要決定是根據(jù)整個對象來判斷,還是根據(jù)其中幾個字段來判斷颂斜。NSArray判斷是先根據(jù)數(shù)組所含個數(shù)是否相同夫壁,若相同,則在每個位置的的兩個對象調(diào)用isEqual沃疮,如果每個位置的對象均相等盒让,這就叫做“深度等同性判斷”。

容器中可變類的等同性

? ? 還有一種情況需要注意司蔬,就是在容器中放入可變類對象邑茄,就不應該再改變其哈希碼了,舉個例子:

NSMutableSet *set = [NSMutableSet new];

NSMutableArray *arrayA = [@[@1,@2] mutableCopy];

[set addObject:arrayA];

NSLog(@"set is %@",set);

//output set is {((1,2))}

? ? 現(xiàn)在set中含有一個數(shù)組對象俊啼,數(shù)組中有兩個元素肺缕,再向set中添加另外一個數(shù)組,此數(shù)組與前一個數(shù)組對象相同,順序也相同:


NSMutableArray *arrayB = [@[@1,@2] mutableCopy];

[set addObject:arrayB];

NSLog(@"set is %@",set);

//output set is {((1,2))}

? ? ?此時set中仍然只有一個對象同木,因為已有的數(shù)組與新添加的數(shù)組相同浮梢,所以set不會改變。這次我們添加一個和set中已有的數(shù)組不同的數(shù)組:


NSMutableArray *arrayC = [@[@1] mutableCopy];

[set addObject:arrayC];

NSLog(@"set is %@",set);

//output set is {((1),(1,2))}

? ? ?如我們所料彤路,set中現(xiàn)在又兩個數(shù)組了黔寇。此時我們改變arrayC,另其和最早的數(shù)組相同

[arrayC addObject:@2];

NSLog(@"set is %@",set);

//output set is {((1,2),(1,2))}

set中居然可以包含兩個相同的數(shù)組斩萌,根據(jù)set語義是不允許這樣的缝裤。此時如果我們copy此set,那就更糟了:

NSSet *setB = [set copy];

NSLog(@"setB is %@",setB);

//output setB is {((1,2))}

復制過來的set中又只剩一個對象了颊郎,此set看上去好像由一個空set開始憋飞,通過逐個向其中添加新對象創(chuàng)造出來的。并不是不可以這么做姆吭,只是如果這么做榛做,就要小心其隱患,并用相應的代碼處理可能發(fā)生的問題内狸。

9检眯、理解objc_msgSend的作用

? ? 對象調(diào)用方法是Objective-C經(jīng)常使用的,用OC的術(shù)語來說昆淡,這叫做“消息傳遞”锰瘸,消息有名稱和選擇器(selector),可以接受參數(shù)而且可能有返回值昂灵。在OC中避凝,如果向某對象傳遞消息,會使用動態(tài)綁定機制來決定需要調(diào)用哪個方法眨补。對象收到消息后管削,調(diào)用哪個方法是運行時決定的,甚至可以再運行時改變撑螺。給對象發(fā)送消息可以這樣來寫:

id retureValue = [someObject messageName:param];

? ? 在上邊這個例子中含思,someObject作為接收者(receiver),messageName作為選擇器和param合起來稱為消息甘晤。編譯器看到此消息后含潘,轉(zhuǎn)換為消息傳遞機制的核心函數(shù),叫做“objc_msgSend”安皱,方法原型如下:

void objc_msgSend(id self, SEL cmd,...)

? ? 這是個“函數(shù)參數(shù)可變的函數(shù)”调鬓,能接受兩個及以上的參數(shù)艇炎,第一個參數(shù)代表接收者酌伊,第二個參數(shù)代表選擇器(SEL是選擇器的類型),后續(xù)參數(shù)就是消息的實際參數(shù)。編譯器會把之前的例子轉(zhuǎn)換成:

id returnValue = objc_msgSend(someObject ,?@selector(messageName),param);

為了完成此操作居砖,消息中心會在接收者的類中搜尋方法(list of method)虹脯,如果能找到實現(xiàn)的代碼,則跳至代碼的實現(xiàn)奏候,若是找不到循集,則沿著繼承體系繼續(xù)往上找,找到合適的方法再跳轉(zhuǎn)蔗草。如果最后還是沒找到咒彤,那就執(zhí)行“消息轉(zhuǎn)發(fā)”操作。前面描述的只是部分調(diào)用過程咒精,比如方法緩存之類的都沒有詳細說明镶柱,后續(xù)會進行詳細說明。其他的邊界情況模叙,則需要交由OC運行環(huán)境中的另外的函數(shù)進行處理歇拆。每個類里都有一張表格,選擇器的名稱作為查表的key范咨,objc_msgSend正是通過表格來尋找應該執(zhí)行的方法并跳轉(zhuǎn)的故觅。

10、了解消息轉(zhuǎn)發(fā)機制

? ? 當對象在收到無法解讀的消息之后會發(fā)生什么渠啊?

? ? 我們會遇到消息轉(zhuǎn)發(fā)流程處理的消息输吏,只是未加留意過,如果在控制臺中顯示以下信息替蛉,說明你曾向某個對象發(fā)送了一條無法解讀的消息评也,從而啟動了消息轉(zhuǎn)發(fā)機制,并轉(zhuǎn)發(fā)給了NSObject默認的實現(xiàn)方式灭返。

-[NSCFNumber lowercaseString]: unrecognized selector sent to instance 0x87

? ??上面這段信息是由NSObject的“doesNotRecognizeSelector”方法拋出的盗迟,此異常表明,消息接受者的類型時NSCFNumber,而該接受者無法理解名為“l(fā)owercaseString”的選擇器熙含。這個例子以程序崩潰告終罚缕,不過在編寫自己的類時,可在轉(zhuǎn)發(fā)過程中掛鉤怎静,用以執(zhí)行預定的邏輯邮弹,不讓程序崩潰。

? ? 消息轉(zhuǎn)發(fā)分為兩個階段蚓聘。第一階段是詢問接收者所屬的類腌乡,是否能動態(tài)添加方法,來處理當前未知的選擇器夜牡,叫做“動態(tài)方法解析”与纽。第二階段涉及“完整的消息轉(zhuǎn)發(fā)機制”。如果運行期已經(jīng)把第一階段執(zhí)行完了,那么接受者就無法再用動態(tài)新增方法的手段來響應包含該選擇器的消息了急迂。此時系統(tǒng)會請求接受者以其他手段來處理與消息相關的方法調(diào)用影所。這又細分為兩小步:首先,請接受者看看有沒有其他對象能處理這條消息僚碎,如果有猴娩,則轉(zhuǎn)發(fā)此消息給這個對象;如果沒有“備援的接受者”勺阐,則啟動完整的消息轉(zhuǎn)發(fā)機制卷中,運行期系統(tǒng)把完整的消息封裝成NSInvocation中,再給接受者最后一次機會渊抽。

動態(tài)方法解析

? ? 對象在收到無法解析的消息時仓坞,首先會調(diào)用以下方法:

+ (BOOL)resolveInstanceMethod:(SEL)selector

? ? 該方法的參數(shù)就是未知的選擇器,返回值為BOOL腰吟,表示是否能新增一個實例方法來處理這個選擇器无埃。假如未實現(xiàn)的方法不是實例方法而是類方法,那么運行期系統(tǒng)會調(diào)用“resolveClassMethod”毛雇。使用這種方法的前提是嫉称,相關方法的實現(xiàn)代碼已經(jīng)寫好,只需要在運行時動態(tài)插在里面就可以了灵疮,此方案常用來處理@dynamic屬性织阅。下面的代碼演示了如何使用“resolveInstanceMethod”來實現(xiàn):

void testResolveInstanceMethod(id self, SEL _cmd, NSString *name);


+(BOOL)resolveInstanceMethod:(SEL)sel{

????NSString *methodString = NSStringFromSelector(sel);

????if ([methodString hasPrefix:@"test"]) {

????????class_addMethod(self, sel, (IMP)testResolveInstanceMethod, "B@:@");

????????return YES;

????}

????return [super resolveInstanceMethod:sel];

}

備援接收者

? ? 當前接收者還有第二次機會處理未知的選擇器,在這一步中震捣,運行期系統(tǒng)會詢問他荔棉,能否將這條消息轉(zhuǎn)發(fā)給其他接收者處理,對應的處理方法如下:

-(id)forwardingTargetForSelector:(SEL)selector

? ? 若當前的接收者能找到備援對象蒿赢,則將其返回润樱,若找不到,返回nil羡棵。通過此方案壹若,我們可以用“組合”來模擬出“多重繼承”的某些特性。在一個對象內(nèi)部皂冰,可能含有一系列的對象店展,該對象可經(jīng)由此方法將能夠處理某選擇器的對象返回,這樣在外界看來秃流,好像是由該對象親自處理的赂蕴。需要注意的是,我們無法操作經(jīng)由這一步所轉(zhuǎn)發(fā)的消息舶胀。如果想在發(fā)送給備援接收者之前修改消息概说,那就只能通過完整的消息轉(zhuǎn)發(fā)機制來做了碧注。

完整的消息轉(zhuǎn)發(fā)

? ? 如果轉(zhuǎn)發(fā)算法到達這一步,那么只能通過完整的消息轉(zhuǎn)發(fā)機制了席怪。首先創(chuàng)建NSInvocation對象,把尚未處理的消息全部封裝到里面纤控,包含選擇器挂捻、目標和參數(shù),在觸發(fā)NSInvocation對象時船万,“消息派發(fā)系統(tǒng)”將親自觸發(fā)刻撒,把消息派發(fā)給對象。調(diào)用如下方法:

- (void)forwardInvocation:(NSInvocation*)invocation;

? ? 這個方法實現(xiàn)比較簡單耿导,只需要改變調(diào)用目標声怔,使消息在新目標可以被調(diào)用即可。通過這種方式和備援接收者方式相同舱呻,比較有用的實現(xiàn)方式為:在觸發(fā)消息前醋火,先以某種方式改變消息內(nèi)容。

? ? 實現(xiàn)此方法時箱吕,若發(fā)現(xiàn)某調(diào)用操作不應由本類處理芥驳,則需調(diào)用超類的同名方法,這樣的話茬高,繼承體系中的每個類都有機會處理此請求兆旬,直至NSObject。如果到了NSObject還未處理怎栽,那么該方法會調(diào)用“doNotRecognizeSelector”以拋出異常丽猬,表明選擇器最終未被處理。

11熏瞄、“方法調(diào)配技術(shù)”–swizzling

? ?在上一節(jié)中脚祟,我們介紹了,對象收到消息之后强饮,具體調(diào)用什么方法需要在運行期執(zhí)行愚铡。類的方法列表會把選擇器的名稱映射到相關的方法實現(xiàn)之上,使得動態(tài)消息派發(fā)系統(tǒng)能夠找到具體實現(xiàn)的方法胡陪。這些函數(shù)均以函數(shù)指針的方式來表示沥寥,這種指針叫做IMP,原型如下

? ?id (*IMP) (id, SEL , ...)?

? ?NSString類可以響應lowercaseString,uppercaseString等選擇器柠座,映射表中的每個選擇器都對應到不同的IMP上邑雅,如下所示:


持續(xù)更新中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市妈经,隨后出現(xiàn)的幾起案子淮野,更是在濱河造成了極大的恐慌捧书,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骤星,死亡現(xiàn)場離奇詭異经瓷,居然都是意外死亡,警方通過查閱死者的電腦和手機洞难,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門舆吮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人队贱,你說我怎么就攤上這事色冀。” “怎么了柱嫌?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵锋恬,是天一觀的道長。 經(jīng)常有香客問我编丘,道長与学,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任嘉抓,我火速辦了婚禮癣防,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掌眠。我一直安慰自己蕾盯,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布蓝丙。 她就那樣靜靜地躺著级遭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渺尘。 梳的紋絲不亂的頭發(fā)上挫鸽,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音鸥跟,去河邊找鬼丢郊。 笑死,一個胖子當著我的面吹牛医咨,可吹牛的內(nèi)容都是我干的枫匾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拟淮,長吁一口氣:“原來是場噩夢啊……” “哼干茉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起很泊,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤角虫,失蹤者是張志新(化名)和其女友劉穎沾谓,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體戳鹅,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡均驶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了枫虏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妇穴。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖模软,靈堂內(nèi)的尸體忽然破棺而出伟骨,到底是詐尸還是另有隱情饮潦,我是刑警寧澤燃异,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站继蜡,受9級特大地震影響回俐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稀并,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一仅颇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碘举,春花似錦忘瓦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蝙场,卻和暖如春凌停,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背售滤。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工罚拟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人完箩。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓赐俗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弊知。 傳聞我的和親對象是個殘疾皇子秃励,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354