觀“編寫高質(zhì)量iOS與OC 代碼的52個(gè)有效方法”有感(二)· 對象秧耗、消息、運(yùn)行時(shí)

MacBook Pro.jpg

6舶治、理解“屬性”這一概念

  • Objective-C面向?qū)ο笳Z言編程分井。
    對象就是“基本構(gòu)造單元”,開發(fā)者用對象存儲并傳遞數(shù)據(jù)霉猛。
    對象之間傳遞數(shù)據(jù)并且執(zhí)行任務(wù)的過程就叫做“消息傳遞”
    程序運(yùn)行起來尺锚。相關(guān)支持的代碼就叫做“Objective-C runtime”。

  • “屬性”是Objective-C的一項(xiàng)特性韩脏,用于封裝對象中的數(shù)據(jù)缩麸。
    Objective-C對象會把數(shù)據(jù)保存為各種實(shí)例變量铸磅。
    實(shí)例變量通過“存取方法”(accessmethod)訪問赡矢。
    getter 用于讀取變量值
    setter用于寫入變量值

  • @property
    對象接口的定義中杭朱,可以使用屬性。 -> 標(biāo)準(zhǔn)的寫法
    編譯器會自動(dòng)寫出一套存取方法吹散,用以訪問給定類型中具有給定名稱的變量弧械。

@property (nonatomic ,copy) NSString *nameString;

等同于下面的這種寫法

- (void)setNameString:(NSString *)nameString;

- (NSString *)nameString;
  • 屬性優(yōu)勢:

    • 編譯器自動(dòng)編寫與訪問這些屬性所需的方法 =“自動(dòng)合成”(autosynthesis)
      這個(gè)過程是由編譯器在編譯時(shí)期執(zhí)行的,所以編輯器看不到這些“合成方法”的源代碼空民。
    • 除了生成方法代碼之外刃唐,編譯器還會自動(dòng)向類中添加適當(dāng)類型的實(shí)例變量,并且添加下劃線作為實(shí)例變量的名字界轩。
      比如上面的名稱就為_nameString画饥。
  • 自己實(shí)現(xiàn)存取方法

    • 使用@dynamic關(guān)鍵字 。告訴編譯器不讓自動(dòng)創(chuàng)建實(shí)例變量浊猾、存取方法抖甘!
  • 屬性特質(zhì)

    • 原子性
      默認(rèn)情況下。編譯器合成的方法通過通過鎖定機(jī)制確實(shí)其原子性(atomicity)葫慎。
      如果屬性具備nonatomic特質(zhì)衔彻,則不使用同步鎖。
    • 讀/寫權(quán)限
      readwrite(讀寫):具有setter和getter方法偷办!
      readonly(只讀):僅有g(shù)etter方法艰额。
    • 內(nèi)存管理
      assign:針對CGFloat或者NSInteger等“純量類型”(基礎(chǔ)數(shù)據(jù)類型 和C數(shù)據(jù)類型)簡單賦值,不更改索引計(jì)算椒涯。
      strong:為屬性設(shè)置新值時(shí)柄沮,保留新值,釋放舊值废岂,再將新值設(shè)置上去铡溪。
      weak:既不保留新值,也不釋放舊值泪喊,同assign棕硫。
      copy:與strong類似,但是并不保留新值袒啼。而是將其“拷貝”哈扮。
      經(jīng)典案列:NSString 確保對象中的字符串值不會無意間改動(dòng)。

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

  • 使_XXX直接訪問實(shí)例變量滑肉。
    • 速度快。不經(jīng)過Objective-C的“方法派發(fā)”(method dispatch)摘仅,編譯器直接訪問保存對象實(shí)例變量的那塊內(nèi)存
    • 直接訪問實(shí)例變量靶庙,不調(diào)取“設(shè)置方法”(setter)這就繞過了內(nèi)存管理語義。
    • 直接訪問實(shí)例變量娃属,也不會觸發(fā)“鍵值觀測”(Key-Value Observing六荒, KVO)
      這樣做是否有問題還是取決于具體的對象行為护姆。
  • 使用self.XXX來訪問
    • 有助于排查與之相關(guān)的錯(cuò)誤,因?yàn)榭梢越o“setter”和“getter”設(shè)置斷點(diǎn)
    • 懶加載也是需要通過“獲取方法”來訪問屬性掏击。否則卵皂。實(shí)例變量永遠(yuǎn)不會初始化。
  • 建議:
    除特殊情況砚亭。
    在讀取實(shí)例變量的時(shí)候采用直接訪問的形式灯变,
    在設(shè)置實(shí)例變量的時(shí)候通過屬性來做。

8捅膘、理解“對象等同性”這一概念

  • 等同性(equality)
    一般情況下相比較我們都是用的 “==” 但是比較出來的結(jié)果未必是我們想要的添祸。
    因?yàn)椤?=”比較是指針本身,而不是其對象寻仗。

  • NSObject中的“isEqual”

    • 判斷兩個(gè)對象的等同性膝捞。
    • NSObject協(xié)議中2個(gè)判斷等同性的關(guān)鍵方法
    - (BOOL)isEqual:(id)object;
    @property (readonly) NSUInteger hash;
    

定義:如果“isEqual:”方法判斷兩個(gè)對象相等,那么其hash方法也必須返回同一個(gè)值愧沟。
如果兩個(gè)對象的hash方法返回同一個(gè)值蔬咬,“isEqual”未必會認(rèn)為兩者相等。

  • NSString實(shí)現(xiàn)了一個(gè)獨(dú)有的等同性判斷方法:isEqualToString
    該方法比“isEqual”快沐寺,因?yàn)樵摲椒爝f對象規(guī)定為NSString林艘。而“isEqual”還要執(zhí)行額外步驟,因?yàn)椤癷sEqual”不知道受測對象類型混坞。

  • NSArray與NSDictionary也有類似的特殊的等同性方法狐援。
    “isEqualToArray”與“isEqualToDictionary”
    如果檢測到受測對象不是數(shù)組或者字典就會拋出異常。

  • 自己實(shí)現(xiàn)等同性方法原理:

    • 首先究孕,判斷兩個(gè)指針是否相等啥酱。相等則說明指向同一對象!
    • 其次厨诸,比較兩個(gè)對象所屬的類(考慮到父類與子類的判斷)
    • 然后镶殷,檢測每個(gè)屬性是否相等(不要盲目逐步檢查每條屬性,而是根據(jù)需求來定制)
    • 最后微酬,實(shí)現(xiàn)hash方法:
      等同性約定:若兩個(gè)對象相等绘趋,則哈希碼相等,但是兩個(gè)哈希碼相同的對象卻未必相等颗管。(應(yīng)使用計(jì)算速度快而且哈希碼碰撞幾率低的算法陷遮,否則會影響性能)
  • 小技巧:

    • 如果要重寫“isEqual”方法。
      如果受測參數(shù)與接收消息對象屬于同一個(gè)類垦江,就調(diào)用自己寫的判定方法帽馋。否則就交給超類來判斷。
    • 等同性的判斷深度。
      如果判斷兩個(gè)對象的所有屬性是否相等绽族,這樣的叫“深度等同性判定”姨涡。
      不過更多時(shí)候是根據(jù)其中部分?jǐn)?shù)據(jù)即可判斷二者是否等同。

9项秉、以“類族模式”隱藏實(shí)現(xiàn)細(xì)節(jié)

  • 類族:把實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡單的公共接口后面绣溜。
  • 例子:
  • 系統(tǒng)框架中有很多類族慷彤。
    比如UIButton創(chuàng)建的時(shí)候的類方法
    UIButton *button = [UIButton buttonWithType:<#(UIButtonType)#>]
    這樣該方法返回的對象娄蔼,決定傳入的按鈕類型。
  • NSArray與可變類型NSMutableArray底哗。
    有兩個(gè)抽象基類岁诉,一個(gè)不可變數(shù)組,一個(gè)可變數(shù)組跋选。
  • 動(dòng)手創(chuàng)建一個(gè)類族:
    • 需求:一個(gè)公司分為2種人:1涕癣、管理者。2前标、工人坠韩。分別干不同的事!
    • 創(chuàng)建一個(gè)基于NSObject的類
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger, SCUserType) {
    SCUserTypeManager,
    SCUserTypeWorker,
};

@interface SCUser : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;


//創(chuàng)建
+ (SCUser *)scUserWithType:(SCUserType)type;

//做事情
- (void)doWork;

@end
  • .m的實(shí)現(xiàn):
#import "SCUser.h"
#import "SCUserWorker.h"
#import "SCUserManager.h"

@implementation SCUser

+ (SCUser *)scUserWithType:(SCUserType)type {
    switch (type) {
        case SCUserTypeManager:
            return [SCUserManager new];
            break;
            
        case SCUserTypeWorker:
            return [SCUserWorker new];
            break;
    }
}

- (void)doWork {
    
}

@end

每個(gè)“實(shí)體子類” 都是從基類繼承來的炼列。比如:

#import "SCUser.h"

@interface SCUserManager : SCUser

@end

//.m的實(shí)現(xiàn)
#import "SCUserManager.h"

@implementation SCUserManager

- (void)doWork {
    NSLog(@"管理者巡邏");
}

@end

10只搁、在既有類中使用關(guān)聯(lián)對象存放自定義數(shù)據(jù)

  • 關(guān)聯(lián)對象(Associated Object)
    為了解決某些情況(無法從對象所屬的類中繼承一個(gè)子類,然后用子類對象存放相關(guān)信息)
    objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    此方法可以給定的鍵和策略為某對象設(shè)置關(guān)聯(lián)對象值

    objc_getAssociatedObject(id object, const void *key)
    

    此方法根據(jù)給定的鍵從某個(gè)對象中獲取相關(guān)對象值
    objc_removeAssociatedObjects(id object)

    此方法移除指定對象的全部關(guān)聯(lián)對象俭尖。

  • 項(xiàng)目中遇到的問題(runtime)
    當(dāng)時(shí)是為了解決NSURL中有個(gè)URLWithString的方法會默認(rèn)把帶中文的鏈接給轉(zhuǎn)碼氢惋。因?yàn)槌绦蛑泻芏嗟胤蕉加玫搅诉@個(gè)方法,很明顯稽犁,一個(gè)一個(gè)的修改是很費(fèi)力氣的焰望。用到了runtime中的一個(gè)交換方法:
    自己實(shí)現(xiàn)一個(gè)函數(shù),然后與系統(tǒng)的函數(shù)交換一下已亥。完美解決問題熊赖。
    主要代碼:

#import <objc/runtime.h>

@implementation NSURL (Unicode)

+ (void)load {
    /*
     self:UIImage
     誰的事情,誰開頭 1.發(fā)送消息(對象:objc) 2.注冊方法(方法編號:sel) 3.交互方法(方法:method) 4.獲取方法(類:class)
     Method:方法名
     
     獲取方法,方法保存到類
     Class:獲取哪個(gè)類方法
     SEL:獲取哪個(gè)方法
     imageName
     */
    // 獲取imageName:方法的地址
    Method URLWithStringMethod = class_getClassMethod(self, @selector(URLWithString:));
    
    // 獲取wg_imageWithName:方法的地址
    Method sc_URLWithStringMethod = class_getClassMethod(self, @selector(sc_URLWithString:));
    
    // 交換方法地址,相當(dāng)于交換實(shí)現(xiàn)方式2
    method_exchangeImplementations(URLWithStringMethod, sc_URLWithStringMethod);
    
}


+ (NSURL *)sc_URLWithString:(NSString *)URLString {
    
    NSString *newURLString = [self IsChinese:URLString];
    return [NSURL sc_URLWithString:newURLString];
}

11虑椎、理解 objc_msgSend 的作用

  • Objective-C中給對象發(fā)消息

    [object message:parameter];
    

    原理:
    objc_msgSend(id self, SEL cmd,...)
    核心函數(shù)秫舌,這個(gè)是“參數(shù)個(gè)數(shù)可變的函數(shù)”,能接收兩個(gè)或者兩個(gè)以上的參數(shù)绣檬。
    第一個(gè)參數(shù)代表接收者足陨。第二個(gè)參數(shù)代表方法的名字。
    上面的OC代碼換成函數(shù)就為:
    objc_msgSend(object, @selector(message:),parameter);
    objc_msgSend函數(shù)根據(jù)接收者和方法名來調(diào)用適當(dāng)?shù)姆椒ā?br> 過程:
    1.先到所屬的類尋找“方法列表”娇未,找到就跳轉(zhuǎn)
    2.找不到墨缘,就會沿著繼承體系繼續(xù)向上查找,找到再跳轉(zhuǎn)。
    3.實(shí)在找不到就執(zhí)行“消息轉(zhuǎn)發(fā)”
    看起來調(diào)用一個(gè)方法需要很多步驟镊讼。但是objc_msgSend會將匹配結(jié)果緩存在“快速映射表”里宽涌。這樣子執(zhí)行就快了。

  • 其他的方法:

    // 待發(fā)送消息返回結(jié)構(gòu)體
    objc_msgSend_stret
    
    //消息返回的是浮點(diǎn)數(shù)
    objc_msgSend_fpret
    
    //給超類發(fā)消息  例如[super XXX];
    objc_msgSendSuper

大家碼代碼時(shí)期能更多的了解一些底層的工作原理蝶棋。在調(diào)試的時(shí)候會幫助你很多卸亮。

12、理解消息轉(zhuǎn)發(fā)機(jī)制

  • 消息轉(zhuǎn)發(fā):
    因?yàn)镺bjective-C中玩裙,在編譯期向類發(fā)送無法解讀的消息并不會報(bào)錯(cuò)兼贸,因?yàn)樵谶\(yùn)行期還可以繼續(xù)向類添加方法。因此吃溅,編譯器在編譯時(shí)無法確定類中到底會不會有某個(gè)方法實(shí)現(xiàn)溶诞。
    當(dāng)對象接受到無法解讀的消息后,就會啟動(dòng)“消息轉(zhuǎn)發(fā)”機(jī)制决侈,程序員可以由此告訴對象如何處理未知的消息螺垢。
    大家在開發(fā)期間肯定見過這樣的錯(cuò)誤:
unrecognized selector sent to instance 0x610000026560
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SCUserWorker sss]: unrecognized selector sent to instance 0x610000026560'

錯(cuò)誤原因:是因?yàn)榻邮照邿o法理解sss的這個(gè)方法名,因此致使程序崩潰赖歌。

  • 對象在接收到無法解讀的消息后枉圃,會依次調(diào)用下列方法。
    + (BOOL)resolveInstanceMethod:(SEL)sel
    在這個(gè)方法中庐冯,參數(shù)就是未知的方法名稱孽亲。在這里你可以解決問題。
    - (id)forwardingTargetForSelector:(SEL)aSelector
    這個(gè)是備援接收者肄扎,也就是給接收者第二次處理的機(jī)會墨林,如果可以找到備援對象則將其返回,若找不到就返回nil犯祠。
  • 完整的消息轉(zhuǎn)發(fā)
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制旭等,首先要?jiǎng)?chuàng)建 NSInvocation 對象,把尚未處理的消息相關(guān)的細(xì)節(jié)全部封與其中(方法名衡载,目標(biāo)以及參數(shù))搔耕。
    使用:只需改變調(diào)用目標(biāo),使消息在新目標(biāo)上得以調(diào)用就好了痰娱,和第二種方法“備援接收者”等效弃榨。
消息轉(zhuǎn)發(fā).png
  • 案列:使用class_addMethod動(dòng)態(tài)添加方法
    假設(shè)我故意一個(gè)類只在.h聲明了方法 沒有在.m中實(shí)現(xiàn)該方法
    結(jié)果就會報(bào)上面的錯(cuò),接收者無法解讀消息梨睁。讓你用runtime動(dòng)態(tài)添加方法你會怎么辦呢鲸睛?

    • 考慮
      原因是因?yàn)闆]有實(shí)現(xiàn)該方法,所以無法解讀坡贺,那么我們要為其添加方法官辈。
      那么這個(gè)方法添加到哪呢箱舞?該如何添加?
    • 動(dòng)手
      首先找到?jīng)]有實(shí)現(xiàn)方法的那個(gè)類拳亿,在其.m添加
      + (BOOL)resolveInstanceMethod:(SEL)sel
      這個(gè)方法晴股。上述講到過,無法解讀消息時(shí)會第一時(shí)間調(diào)用這個(gè)方法肺魁,我們可以在這來解決問題电湘。
      接下來要用到runtime中的 class_addMethod 方法
      class_addMethod(__unsafe_unretained Class cls, SEL name, IMP imp, const char *types)
      1.Class cls : 參數(shù)表示添加新方法的類
      2.SEL name : 表示方法名稱
      3.IMP imp : 表示由編譯器生成的、指向?qū)崿F(xiàn)方法的指針鹅经。也就是說寂呛,這個(gè)指針指向的方法就是我們要添加的方法。
      4.const char **types :最后一個(gè)參數(shù) *types 表示我們要添加的方法的返回值和參數(shù)瞬雹。
      主要代碼在下面:
      eat:只聲明沒有實(shí)現(xiàn)的方法昧谊。
      SCUser:創(chuàng)建的類刽虹。
  • C語言函數(shù)的實(shí)現(xiàn)
    記得導(dǎo)入
    #import <objc/runtime.h>

void sayHello (id self,SEL _cmd) {
    NSLog(@"Hello");
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    if (sel == @selector(eat)) {
        class_addMethod([SCUser class], sel, (IMP)sayHello, "v@:@");
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
};
  • OC形式的實(shí)現(xiàn)
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    if (sel == @selector(eat)) {
        class_addMethod([SCUser class], sel, class_getMethodImplementation(self, @selector(sayHello)), "v@:@");
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
};



- (void)sayHello {
    NSLog(@"hahaha");
}

13酗捌、用“方法調(diào)配技術(shù)”調(diào)試“黑盒方法”

  • 在第10條中有介紹過交換方法的案列。
  • 交換方法:
  • 在運(yùn)行期涌哲,向類中新增或者替換方法胖缤。
  • 使用另一個(gè)方法替換一個(gè)方法可以向其添加新功能。
  • 只有調(diào)試程序中才會用的運(yùn)行期修改方法阀圾,不宜濫用哪廓。

14、理解“類對象”的用意

  • 看下面的代碼
    NSString *nameStirng = @"小伙子";
    可以理解:nameString 為存放內(nèi)存地址的變量初烘。而NSString自身的數(shù)據(jù)就存在地址中涡真。所有的Objective-C對象都是如此。
  • 還可以這樣寫:
    id nicknameStirng = @"牛";
    對于通用的對象類型id肾筐,因?yàn)槠渥陨硪呀?jīng)是指針了哆料。所以可以這樣寫。
  • 比較
    兩者語法意義相同吗铐,
    唯一區(qū)別:如果聲明的時(shí)候指定了具體類型东亦,那么在該類實(shí)例上調(diào)用沒有的方法時(shí),編譯器會發(fā)出警告信息唬渗。
  • id的定義
typedef struct object {
    Class isa;
} *id;

說明每個(gè)對象結(jié)構(gòu)體的首個(gè)成員是Class類的變量典阵。通常稱為“isa”指針。

  • metaclass
    metaclass就是isa指向的一個(gè)結(jié)構(gòu)體镊逝。
  • 舉例
    用一個(gè)例子說明:
    大學(xué)期間壮啊,小明的輔導(dǎo)員要調(diào)查小明家里有沒有黨員。
    首先撑蒜,輔導(dǎo)員通過身份證號找到小明的檔案歹啼,發(fā)現(xiàn)小明不是黨員充坑,從小明的檔案中發(fā)現(xiàn)小明父母的身份證號,通過小明父母的身份證號找到小明父母的檔案染突,發(fā)現(xiàn)小明父母都是黨員捻爷。
    身份證號 = isa ,檔案 = metaclass份企。
    (這是作者自己的粗淺理解也榄,如果不對,歡迎指出)
  • 檢測繼承體系
    • isKindOfClass
      isKindOfClass來確定一個(gè)對象是否是一個(gè)類的成員司志,或者是派生自該類的成員甜紫。
    • isMemberOfClass
      isMemberOfClass只能確定一個(gè)對象是否是當(dāng)前類的成員。

接下來也將會繼續(xù)整理骂远。如果覺得有用請點(diǎn)個(gè)喜歡囚霸!

您的支持將是我繼續(xù)寫作的動(dòng)力!謝謝激才。

觀“編寫高質(zhì)量iOS與OC X代碼的52個(gè)有效方法”有感(一)· 熟悉Objective-C
觀“編寫高質(zhì)量iOS與OC X代碼的52個(gè)有效方法”有感(二)· 對象拓型、消息、運(yùn)行時(shí)
觀“編寫高質(zhì)量iOS與OC X代碼的52個(gè)有效方法”有感(三)· 接口與API設(shè)計(jì)
觀“編寫高質(zhì)量iOS與OC X代碼的52個(gè)有效方法”有感(四)· 協(xié)議與分類

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瘸恼,一起剝皮案震驚了整個(gè)濱河市劣挫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌东帅,老刑警劉巖压固,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異靠闭,居然都是意外死亡帐我,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門愧膀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拦键,“玉大人,你說我怎么就攤上這事扇调】蠊荆” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵狼钮,是天一觀的道長碳柱。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任救湖,我火速辦了婚禮,結(jié)果婚禮上瑞侮,老公的妹妹穿的比我還像新娘的圆。我一直安慰自己,他們只是感情好半火,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布越妈。 她就那樣靜靜地躺著,像睡著了一般钮糖。 火紅的嫁衣襯著肌膚如雪梅掠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天店归,我揣著相機(jī)與錄音阎抒,去河邊找鬼。 笑死消痛,一個(gè)胖子當(dāng)著我的面吹牛且叁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秩伞,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼逞带,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了稠歉?” 一聲冷哼從身側(cè)響起掰担,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤汇陆,失蹤者是張志新(化名)和其女友劉穎怒炸,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毡代,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡阅羹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了教寂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捏鱼。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酪耕,靈堂內(nèi)的尸體忽然破棺而出导梆,到底是詐尸還是另有隱情,我是刑警寧澤迂烁,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布看尼,位于F島的核電站,受9級特大地震影響盟步,放射性物質(zhì)發(fā)生泄漏藏斩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一却盘、第九天 我趴在偏房一處隱蔽的房頂上張望狰域。 院中可真熱鬧媳拴,春花似錦、人聲如沸兆览。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抬探。三九已至语婴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間驶睦,已是汗流浹背砰左。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留场航,地道東北人缠导。 一個(gè)月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像溉痢,于是被迫代替她去往敵國和親僻造。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

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