OC底層原理07-類的結(jié)構(gòu)分析

一膳灶、類的本質(zhì)

《OC底層原理04-對(duì)象的本質(zhì)》那篇文章中解滓,我們講到了如何將.m文件編譯成.cpp文件查看底層結(jié)構(gòu)碘梢,這里就不作過多贅述

1.1 在cpp文件找查找Class的定義

typedef struct objc_class *Class;
  • main.cpp中,找到了底層關(guān)于Class的定義伐蒂,類是一個(gè)objc_class類型的結(jié)構(gòu)體

1.2 接著進(jìn)入objc4源碼查找objc_class煞躬,源碼相關(guān)可以查閱《OC底層原理02-iOS_objc4-781.2 最新源碼編譯調(diào)試》

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    //: 由于代碼量過大,這里只展示關(guān)鍵代碼,源碼請(qǐng)自行查閱
}
  • objc_class是一個(gè)結(jié)構(gòu)體恩沛,所以進(jìn)一步再次說明類也是一個(gè)結(jié)構(gòu)體
  • objc_class繼承于objc_object 在扰,類也是對(duì)象,萬物皆對(duì)象
  • objc_class繼承了objc_objectisa屬性雷客,所以類的地址第一位仍然存的是isa
  • superclassobjc_object類型的結(jié)構(gòu)體指針
  • cache:緩存
  • bits:存儲(chǔ)屬性芒珠,實(shí)例方法,協(xié)議

總結(jié):類的本質(zhì)是一個(gè)objc_class類型的結(jié)構(gòu)體

二搅裙、 探索objc_class中的bits

類不能像對(duì)象那樣直接斷點(diǎn)調(diào)試打印皱卓,只有先從源碼入手,分析源碼部逮,并且引入二種分析方法:

  • 地址平移:通過首地址+前面屬性所占內(nèi)存娜汁,平移到我們需要的存儲(chǔ)屬性(bits)的內(nèi)存地址處 (文章結(jié)尾拓展有講到)
  • *():輸出指針類型的對(duì)象

2.1 通過閱讀源碼定位bits內(nèi)存地址

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }
    //: 由于代碼量過大,這里只展示關(guān)鍵代碼兄朋,源碼請(qǐng)自行查閱
}
2.1.1 第一位屬性:isa 的內(nèi)存大小
  • 由于objc_class繼承于objc_object掐禁,繼承屬性isa,占8字節(jié)
2.1.2 第二位屬性:superclass 的內(nèi)存大小
typedef struct objc_class *Class;
  • Class是一個(gè)objc_class結(jié)構(gòu)體颅和,superclassClass指針傅事,結(jié)構(gòu)體指針大小為8,指向NSObject類峡扩,占8字節(jié)
2.1.3 第三位屬性:cache 的內(nèi)存大小
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;
#if __LP64__
    uint16_t _flags;
#endif
    uint16_t _occupied;
//: 由于代碼量過大蹭越,這里只展示關(guān)鍵代碼,源碼請(qǐng)自行查閱
  • cache_t結(jié)構(gòu)體中有大量static類型的方法和變量教届,還有大量其他方法般又。
  • static申明的變量和方法不計(jì)入結(jié)構(gòu)體內(nèi)存,不會(huì)存在結(jié)構(gòu)體中巍佑。
  • 方法也不會(huì)存在結(jié)構(gòu)體中茴迁,也不計(jì)入結(jié)構(gòu)體內(nèi)存
  • cache_t大小由_buckets_mask萤衰、_flags堕义、_occupied來決定
  • _buckets是一個(gè)結(jié)構(gòu)體指針<struct bucket_t *>,占8字節(jié)
  • _mask源碼聲明:typedef uint32_t mask_t脆栋,uint32_t源碼聲明:typedef unsigned int uint32_t倦卖,占4字節(jié)
  • _flags_occupied都是uint16_tuint16_t源碼聲明:typedef unsigned short uint16_t椿争,各占2字節(jié)
  • 所以計(jì)算出cache占16字節(jié)怕膛,8+4+2+2
2.1.4 結(jié)論
  • 只要把GomuPerson首地址平移32位(isa[8位]+superclasss[8位]+ cache[16位]),就能拿到研究對(duì)象bits的指針地址

2.2 通過lldb調(diào)試拿到bits中的方法秦踪、屬性褐捻、協(xié)議

2.2.2 準(zhǔn)備工作
GomuPerson.h
@protocol TestProtocol <NSObject>

@end

@interface GomuPerson : NSObject
{
    NSString *hobby;
}
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *sex;

- (void)sayNO;
+ (void)sayLove;

GomuPerson.m
- (void)sayNO{}
+ (void)sayLove{}
  • objc4工程中創(chuàng)建類GomuPerson
  • GomuPerson.h中創(chuàng)建屬性name掸茅,sex,協(xié)議TestProtocol柠逞,實(shí)例屬性hobby昧狮,實(shí)例方法sayNO,類方法sayLove
  • GomuPerson.m中實(shí)現(xiàn)實(shí)例方法sayNO板壮、類方法sayLove
2.2.2 獲取類GomuPerson的首地址
//: 方法一
(lldb) p/x GomuPerson.class
(Class) $0 = 0x0000000100002320 GomuPerson
//: 得到地址 `0x0000000100002488 `
//: 方法二
(lldb) x/4gx person
0x1010297b0: 0x001d800100002325 0x0000000000000000
0x1010297c0: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x001d800100002325 & 0x00007ffffffffff8ULL
(unsigned long long) $2 = 0x0000000100002320
//: 得到地址 `0x0000000100002320 `
  • 得到GomuPerson的首地址0x0000000100002320
2.2.2 把GomuPerson的首地址平移32位
(lldb) p/x 0x0000000100002320 + 32
(long) $3 = 0x0000000100002340
  • 得到bits的地址0x0000000100002340
2.2.3 根據(jù)源碼拿到bits.data()
//: 源碼
class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
    return bits.data();
}

//: lldb拿data()
//: 強(qiáng)轉(zhuǎn)(class_data_bits_t *)類型
(lldb) p (class_data_bits_t *)$3
(class_data_bits_t *) $4 = 0x0000000100002340
//: 取出data()逗鸣,指針取值用->
(lldb) p $4->data()
(class_rw_t *) $5 = 0x00000001006b0460
//: 去指針化
(lldb) p *($5)
(class_rw_t) $6 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294975768
  }
  firstSubclass = nil  //: 子類
  nextSiblingClass = NSUUID
}
2.2.4 在源碼中查看class_rw_t
struct class_rw_t {
    //: 由于代碼量過大,這里只展示關(guān)鍵代碼绰精,源碼請(qǐng)自行查閱
    //: 獲取ro()
    const class_ro_t *ro() const {
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>()->ro;
        }
        return v.get<const class_ro_t *>();
    }
    //: 獲取方法
    const method_array_t methods() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
        }
    }
    // 獲取屬性
    const property_array_t properties() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>()->baseProperties};
        }
    }
    // 獲取協(xié)議
    const protocol_array_t protocols() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>()->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
        }
    }
}
  • class_rw_t源碼中撒璧,找到methods()properties()笨使、protocols()
2.2.5 獲取方法列表methods()中存的方法
//: 獲取methods()
(lldb) p $6.methods()
(const method_array_t) $7 = {
  list_array_tt<method_t, method_list_t> = {
     = {
      list = 0x0000000100002160
      arrayAndFlag = 4294975840
    }
  }
}

//: 獲取methods()中的list
(lldb) p $7.list
(method_list_t *const) $8 = 0x0000000100002160
//: 去指針化
(lldb) p *($8)
(method_list_t) $9 = {
  entsize_list_tt<method_t, method_list_t, 3> = {
    entsizeAndFlags = 26
    count = 6
    first = {
      name = "sayNO"
      types = 0x0000000100000f4c "v16@0:8"
      imp = 0x0000000100000da0 (GomuTest`-[GomuPerson sayNO])
    }
  }
}

// count = 6 卿樱,我們打印一下這6個(gè)元素
(lldb) p $9.get(0)
(method_t) $10 = {
  name = "sayNO"
  types = 0x0000000100000f4c "v16@0:8"
  //: 拿到 sayNO
  imp = 0x0000000100000da0 (GomuTest`-[GomuPerson sayNO])
}
(lldb) p $9.get(1)
(method_t) $11 = {
  name = "sex"
  types = 0x0000000100000f60 "@16@0:8"
  //: 系統(tǒng)自動(dòng)生成get方法
  imp = 0x0000000100000e00 (GomuTest`-[GomuPerson sex])
}
(lldb) p $9.get(2)
(method_t) $12 = {
  name = "setSex:"
  types = 0x0000000100000f68 "v24@0:8@16"
  //: 系統(tǒng)自動(dòng)生成set方法
  imp = 0x0000000100000e20 (GomuTest`-[GomuPerson setSex:])
}
(lldb) p $9.get(3)
(method_t) $13 = {
  name = ".cxx_destruct"
  types = 0x0000000100000f4c "v16@0:8"
  //: 系統(tǒng)自動(dòng)生成c++函數(shù)
  imp = 0x0000000100000e50 (GomuTest`-[GomuPerson .cxx_destruct])
}
(lldb) p $9.get(4)
(method_t) $14 = {
  name = "name"
  types = 0x0000000100000f60 "@16@0:8"
  //: 系統(tǒng)自動(dòng)生成get方法
  imp = 0x0000000100000db0 (GomuTest`-[GomuPerson name])
}
(lldb) p $9.get(5)
(method_t) $15 = {
  name = "setName:"
  types = 0x0000000100000f68 "v24@0:8@16"
  //: 系統(tǒng)自動(dòng)生成set方法
  imp = 0x0000000100000dd0 (GomuTest`-[GomuPerson setName:])
}
  • 實(shí)例方法(sayNo)確定存在bits里面
  • 除了我們自定義的實(shí)例方法,系統(tǒng)在編譯中自動(dòng)幫我們實(shí)現(xiàn)了屬性get阱表、set方法([GomuPerson sex]殿如、[GomuPerson setSex:]贡珊、[GomuPerson name]最爬、[GomuPerson name])
  • 除此之外,系統(tǒng)還實(shí)現(xiàn)了.cxx_destruct门岔,c++的方法爱致,因?yàn)?code>OC是底層是封裝的c++,所以會(huì)默認(rèn)添加
  • 類方法sayLove沒有存在bits
  • 系統(tǒng)在編譯中沒有給實(shí)例屬性hobby生成get寒随、set方法
2.2.6 獲取屬性列表properties()中存的屬性
//: 獲取properties()
(lldb) p $6.properties()
(const property_array_t) $16 = {
  list_array_tt<property_t, property_list_t> = {
     = {
      list = 0x0000000100002260
      arrayAndFlag = 4294976096
    }
  }
}

//: 獲取properties()中的list
(lldb) p $16.list
(property_list_t *const) $17 = 0x0000000100002260
//: 去指針化
(lldb) p *($17)
(property_list_t) $18 = {
  entsize_list_tt<property_t, property_list_t, 0> = {
    entsizeAndFlags = 16
    count = 2
    first = (name = "name", attributes = "T@\"NSString\",&,N,V_name")
  }
}

// count = 2 糠悯,我們打印一下這2個(gè)元素
(lldb) p $18.get(0)
(property_t) $19 = (name = "name", attributes = "T@\"NSString\",&,N,V_name")
(lldb) p $18.get(1)
(property_t) $20 = (name = "sex", attributes = "T@\"NSString\",&,N,V_sex")
(lldb) 
  • properties()中只存了屬性namesex妻往。
  • 實(shí)例屬性hobby沒有存在properties()
2.2.7 獲取協(xié)議列表protocols()中存的協(xié)議
(lldb) p $6.protocols()
(const protocol_array_t) $7 = {
  list_array_tt<unsigned long, protocol_list_t> = {
     = {
      list = 0x0000000000000000
      arrayAndFlag = 0
    }
  }
}
(lldb) p $7.list
(protocol_list_t *const) $6 = 0x0000000000000000
//: $6 是個(gè)空互艾,全為0
  • 協(xié)議也沒有存在protocols

2.3 探索實(shí)例屬性、類方法讯泣、協(xié)議存在哪

2.3.1 實(shí)例屬性存儲(chǔ)探索
//: 拿到`GomuPerson`首地址
(lldb) p/x GomuPerson.class
(Class) $0 = 0x0000000100002320 GomuPerson
//: 地址平移32位
(lldb) p/x 0x0000000100002320 + 32
(long) $1 = 0x0000000100002340
//: 強(qiáng)轉(zhuǎn)成(class_data_bits_t *)類型
(lldb) p (class_data_bits_t *)$1
(class_data_bits_t *) $2 = 0x0000000100002340
//: 取data()
(lldb) p $2->data()
(class_rw_t *) $3 = 0x00000001007646a0
// 去指針化
(lldb) p *($3)
(class_rw_t) $4 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294975768
  }
  firstSubclass = nil
  nextSiblingClass = NSUUID
}
// 拿到ro()纫普,同上面的`methods()`
(lldb) p $4.ro()
(const class_ro_t *) $5 = 0x0000000100002118
// 去指針化
(lldb) p *$5
(const class_ro_t) $6 = {
  flags = 388
  instanceStart = 8
  instanceSize = 32
  reserved = 0
  ivarLayout = 0x0000000100000f03 "\x03"
  name = 0x0000000100000ef8 "GomuPerson"
  baseMethodList = 0x0000000100002160
  baseProtocols = 0x0000000000000000
  ivars = 0x00000001000021f8
  weakIvarLayout = 0x0000000000000000
  baseProperties = 0x0000000100002260
  _swiftMetadataInitializer_NEVER_USE = {}
}
//: 拿到ivars
(lldb) p $6.ivars
(const ivar_list_t *const) $7 = 0x00000001000021f8
//: 去指針化
(lldb) p *$7
(const ivar_list_t) $8 = {
  entsize_list_tt<ivar_t, ivar_list_t, 0> = {
    entsizeAndFlags = 32
    count = 3
    first = {
      offset = 0x0000000100002290
      name = 0x0000000100000f0d "hobby"
      type = 0x0000000100000f54 "@\"NSString\""
      alignment_raw = 3
      size = 8
    }
  }
}
// 由于 ivar_list_t 是一個(gè)數(shù)組,所以直接get
(lldb) p $8.get(0)
(ivar_t) $9 = {
  offset = 0x0000000100002290
  //: 找到實(shí)例屬性`hobby `
  name = 0x0000000100000f0d "hobby"
  type = 0x0000000100000f54 "@\"NSString\""
  alignment_raw = 3
  size = 8
}
(lldb) p $8.get(1)
(ivar_t) $10 = {
  offset = 0x0000000100002298
  //: 系統(tǒng)自動(dòng)給屬性生成`_name `實(shí)例屬性
  name = 0x0000000100000f13 "_name"
  type = 0x0000000100000f54 "@\"NSString\""
  alignment_raw = 3
  size = 8
}
(lldb) p $8.get(2)
(ivar_t) $11 = {
  offset = 0x00000001000022a0
  //: 系統(tǒng)自動(dòng)給屬性生成`_sex`實(shí)例屬性
  name = 0x0000000100000f19 "_sex"
  type = 0x0000000100000f54 "@\"NSString\""
  alignment_raw = 3
  size = 8
}
  • 實(shí)例屬性hobby存在ro
  • 系統(tǒng)在編譯中還是給屬性自動(dòng)生成實(shí)例屬性_name好渠、_sex
2.3.2 類方法存儲(chǔ)探索
2.3.2.1 查看源碼
struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods;
    struct method_list_t *classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;
   
    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
    
    protocol_list_t *protocolsForMeta(bool isMeta) {
        if (isMeta) return nullptr;
        else return protocols;
    }
};
  • instanceMethodsclassMethods都是method_list_t類型
  • 發(fā)現(xiàn)methodsForMeta這個(gè)方法昨稼,如果是元類,則返回類方法列表拳锚,如果不是元類假栓,則返回實(shí)例方法列表
  • 猜想,類方法存在元類
2.3.2.1 通過lldb調(diào)試元類霍掺,驗(yàn)證猜想
//: 拿到`GomuPerson`內(nèi)存地址
(lldb) x/4gx GomuPerson.class
0x100002320: 0x00000001000022f8 0x0000000100334140
0x100002330: 0x000000010032e410 0x0000802c00000000
//: isa & mask
(lldb) p/x 0x00000001000022f8 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x00000001000022f8
//: 打印$1匾荆,GomuPerson的元類還是GomuPerson類型
(lldb) po $1
GomuPerson
//: 平移32位
(lldb) p/x $1 + 32
(unsigned long long) $2 = 0x0000000100002318
//: 強(qiáng)轉(zhuǎn)成(class_data_bits_t *)類型
(lldb) p (class_data_bits_t *)$2
(class_data_bits_t *) $3 = 0x0000000100002318
//: 取data()
(lldb) p $3->data()
(class_rw_t *) $4 = 0x000000010104bee0
//: 去指針化
(lldb) p *$4
(class_rw_t) $5 = {
  flags = 2684878849
  witness = 1
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294975664
  }
  firstSubclass = nil
  nextSiblingClass = 0x00007fff8c84bc60
}
//: 拿到methods()
(lldb) p $5.methods()
(const method_array_t) $6 = {
  list_array_tt<method_t, method_list_t> = {
     = {
      list = 0x00000001000020f8
      arrayAndFlag = 4294975736
    }
  }
}
//: 取出methods()里面的list
(lldb) p $6.list
(method_list_t *const) $7 = 0x00000001000020f8
(lldb) p *$7
(method_list_t) $8 = {
  entsize_list_tt<method_t, method_list_t, 3> = {
    entsizeAndFlags = 26
    count = 1
    first = {
      name = "sayLove"
      types = 0x0000000100000f4c "v16@0:8"
      //: 找到類方法sayLove
      imp = 0x0000000100000d90 (GomuTest`+[GomuPerson sayLove])
    }
  }
}
2.3.3 協(xié)議的存儲(chǔ)探索

暫時(shí)沒探索到拌蜘,后面找機(jī)會(huì)補(bǔ)起
三、拓展知識(shí)

3.1 內(nèi)存平移

3.1.1 普通指針
int num1 = 20;
int num2 = 20;
int num3 = 20;
NSLog(@"%d---%p",num1,&num1);
NSLog(@"%d---%p",num2,&num2);
NSLog(@"%d---%p",num3,&num3);

//: 打印
20---0x7ffeefbff57c
20---0x7ffeefbff580
20---0x7ffeefbff584
  • num1棋凳、num2拦坠、num3都指向10,這個(gè)10系統(tǒng)編譯中就已經(jīng)存到了某段內(nèi)存中剩岳,num1贞滨、num2num3的地址卻不一樣拍棕,這就叫值拷貝晓铆,也叫淺拷貝
  • num1num2绰播、num3地址之間相差4字節(jié)骄噪,內(nèi)存連續(xù)
  • 如下圖


    image.png
3.1.2 對(duì)象指針
GomuPerson *person1 = [GomuPerson alloc];
GomuPerson *person2 = [GomuPerson alloc];
GomuPerson *person3 = [GomuPerson alloc];
        
NSLog(@"%p---%p",person1,&person1);
NSLog(@"%p---%p",person2,&person2);
NSLog(@"%p---%p",person3,&person3);

//: 打印
0x102230b50---0x7ffeefbff570
0x102234b00---0x7ffeefbff578
0x102234b20---0x7ffeefbff580
  • person1person2 蠢箩、person3指針链蕊,指向各自[GomuPerson alloc]開辟的內(nèi)存,&person1 谬泌、&person2 滔韵、&person3是指向person1person2 掌实、person3對(duì)象指針的地址陪蜻,這個(gè)指針就是二級(jí)指針
  • 如下圖


    image.png
3.1.3 數(shù)組指針
int arr[4] = {1,2,3,4};
int *d = arr;
NSLog(@"%p -- %p - %p", &arr, &arr[0], &arr[1]);
NSLog(@"%p -- %p - %p", d, d+1, d+2);

//: 打印
0x7ffeefbff570 -- 0x7ffeefbff570 - 0x7ffeefbff574
0x7ffeefbff570 -- 0x7ffeefbff574 - 0x7ffeefbff578
  • &arr&arr[0]贱鼻、d都是取的第一個(gè)地址宴卖,說明數(shù)組的首地址就是第一個(gè)元素的地址
  • 通過地址平移d+1,我們?nèi)〉搅?code>arr[1]邻悬,數(shù)組指針地址平移症昏,按照數(shù)組下標(biāo)平移,內(nèi)存中就是按照元素類型所占內(nèi)存進(jìn)行平移父丰, 0x7ffeefbff574 -> 0x7ffeefbff578肝谭,因?yàn)槭莍nt類型所以平移4
  • 依次類推,結(jié)構(gòu)體中也可以用地址平移的方式去拿不能直接拿到的屬性
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末础米,一起剝皮案震驚了整個(gè)濱河市分苇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屁桑,老刑警劉巖医寿,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蘑斧,居然都是意外死亡靖秩,警方通過查閱死者的電腦和手機(jī)须眷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沟突,“玉大人花颗,你說我怎么就攤上這事』菔茫” “怎么了扩劝?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長职辅。 經(jīng)常有香客問我棒呛,道長,這世上最難降的妖魔是什么域携? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任簇秒,我火速辦了婚禮,結(jié)果婚禮上秀鞭,老公的妹妹穿的比我還像新娘趋观。我一直安慰自己,他們只是感情好锋边,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布皱坛。 她就那樣靜靜地躺著,像睡著了一般宠默。 火紅的嫁衣襯著肌膚如雪麸恍。 梳的紋絲不亂的頭發(fā)上灵巧,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天搀矫,我揣著相機(jī)與錄音,去河邊找鬼刻肄。 笑死瓤球,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的敏弃。 我是一名探鬼主播卦羡,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼麦到!你這毒婦竟也來了绿饵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤瓶颠,失蹤者是張志新(化名)和其女友劉穎拟赊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粹淋,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吸祟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年瑟慈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屋匕。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡葛碧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出过吻,到底是詐尸還是另有隱情进泼,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布纤虽,位于F島的核電站缘琅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏廓推。R本人自食惡果不足惜刷袍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望樊展。 院中可真熱鬧呻纹,春花似錦、人聲如沸专缠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涝婉。三九已至哥力,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間墩弯,已是汗流浹背吩跋。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渔工,地道東北人锌钮。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像引矩,于是被迫代替她去往敵國和親梁丘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356