iOS底層原理探索— Runtime之isa的本質(zhì)

探索底層原理托享,積累從點(diǎn)滴做起骚烧。大家好,我是Mars闰围。

往期回顧

iOS底層原理探索—OC對象的本質(zhì)
iOS底層原理探索—class的本質(zhì)
iOS底層原理探索—KVO的本質(zhì)
iOS底層原理探索— KVC的本質(zhì)
iOS底層原理探索— Category的本質(zhì)(一)
iOS底層原理探索— Category的本質(zhì)(二)
iOS底層原理探索— 關(guān)聯(lián)對象的本質(zhì)
iOS底層原理探索— block的本質(zhì)(一)
iOS底層原理探索— block的本質(zhì)(二)

今天繼續(xù)帶領(lǐng)大家探索iOS之Runtime的本質(zhì)赃绊。

前言

OC是一門動(dòng)態(tài)性比較強(qiáng)的編程語言,它的動(dòng)態(tài)性是基于RuntimeAPI羡榴。Runtime在我們的實(shí)際開發(fā)中占據(jù)著重要的地位碧查,在面試過程中也經(jīng)常遇到Runtime相關(guān)的面試題,我們在之前幾期的探索分析時(shí)也經(jīng)常會(huì)到Runtime的底層源碼中查看相關(guān)實(shí)現(xiàn)校仑。Runtime對于iOS開發(fā)者的重要性不言而喻忠售,想要學(xué)習(xí)和掌握Runtime的相關(guān)技術(shù),就要從Runtime底層的一些常用數(shù)據(jù)結(jié)構(gòu)入手迄沫。掌握了它的底層結(jié)構(gòu)稻扬,我們學(xué)習(xí)起來也能達(dá)到事半功倍的效果。今天先學(xué)習(xí)isa羊瘩。

isa

我們在iOS底層原理探索—OC對象的本質(zhì)一文中講解OC對象本質(zhì)的時(shí)候提到泰佳,每個(gè)OC對象的底層結(jié)構(gòu)體中都包含一個(gè)isa指針:

struct NSObject_IMPL {
    Class isa;
};

arm64架構(gòu)之前,isa僅是一個(gè)指針尘吗,保存著類對象(Class)或元類對象(Meta-Class)的內(nèi)存地址乐纸,在arm64架構(gòu)之后,蘋果對isa進(jìn)行了優(yōu)化摇予,變成了一個(gè)isa_t類型的共用體(union)結(jié)構(gòu)汽绢,同時(shí)使用位域來存儲更多的信息:

isa.h中objc_object部分代碼.png

也就是說,我們之前熟知的OC對象的isa指針并不是直接指向類對象或者元類對象的內(nèi)存地址侧戴,而是需要&ISA_MASK通過位運(yùn)算才能獲取到類對象或者元類對象的地址宁昭。

現(xiàn)在大家可能心存疑問跌宛,什么是共用體?什么是位域积仗?位運(yùn)算又是什么疆拘?不要著急,接下來一一為大家解答寂曹。

1哎迄、位域

位域是指信息在存儲時(shí),并不需要占用一個(gè)完整的字節(jié)隆圆, 而只需占一個(gè)或幾個(gè)二進(jìn)制位漱挚。例如生活中的電燈開關(guān),它只有“開”渺氧、“關(guān)”兩種狀態(tài)旨涝,那我們就可以用 10 來分別代表這兩種狀態(tài),這樣我們就僅僅用了一個(gè)二進(jìn)制位就保存了開關(guān)的狀態(tài)侣背。這樣一來不僅節(jié)省存儲空間白华,還使處理更加簡便。

2贩耐、位運(yùn)算符

在計(jì)算機(jī)語言中弧腥,除了加、減潮太、乘鸟赫、除等這樣的算術(shù)運(yùn)算符之外還有很多運(yùn)算符,這里只為大家簡單講解一下位運(yùn)算符消别。
位運(yùn)算符用來對二進(jìn)制位進(jìn)行操作抛蚤,當(dāng)然,操作數(shù)只能為整型和字符型數(shù)據(jù)寻狂。C語言中六種位運(yùn)算符: & 按位與岁经、 | 按位或、 ^ 按位異或蛇券、 ~ 非缀壤、 << 左移和 >> 右移。
我們依舊引用上面的電燈開關(guān)論纠亚,只不過現(xiàn)在我們有兩個(gè)開關(guān)塘慕,1代表開,0代表關(guān)蒂胞。

1) 按位與 &

有0出0图呢,全1為1。

按位與.png

我們可以理解為在按位與運(yùn)算中,兩個(gè)開關(guān)是串聯(lián)的蛤织,如果我們想要燈亮赴叹,需要兩個(gè)開關(guān)都打開燈才會(huì)亮,所以是1 & 1 = 1指蚜。如果任意一個(gè)開關(guān)沒打開乞巧,燈都不會(huì)亮,所以其他運(yùn)算都是0摊鸡。

2) 按位或 |

有1出1绽媒,全0出0。


按位或.png

在按位或運(yùn)算中免猾,我們可以理解為兩個(gè)開關(guān)是并聯(lián)的是辕,即一個(gè)開關(guān)開,燈就會(huì)亮掸刊。只有當(dāng)兩個(gè)開關(guān)都是關(guān)的,燈才不會(huì)亮赢乓。

3) 按位異或 ^

相同為0忧侧,不同為1。


按位異或.png

4) 非 ~

非運(yùn)算即取反運(yùn)算牌芋,在二進(jìn)制中 1 變 0 蚓炬,0 變 1。例如110101進(jìn)行非運(yùn)算后為001010躺屁,即1010肯夏。

5) 左移 <<

左移運(yùn)算就是把<<左邊的運(yùn)算數(shù)的各二進(jìn)位全部左移若干位,移動(dòng)的位數(shù)即<<右邊的數(shù)的數(shù)值犀暑,高位丟棄驯击,低位補(bǔ)0。
左移n位就是乘以2的n次方耐亏。例如:a<<4是指把a(bǔ)的各二進(jìn)位向左移動(dòng)4位徊都。如a=00000011(十進(jìn)制3),左移4位后為00110000(十進(jìn)制48)广辰。

6) 右移 >>

右移運(yùn)算就是把>>左邊的運(yùn)算數(shù)的各二進(jìn)位全部右移若干位暇矫,>>右邊的數(shù)指定移動(dòng)的位數(shù)。例如:設(shè) a=15择吊,a>>2 表示把00001111右移為00000011(十進(jìn)制3)李根。

簡單了解了位運(yùn)算符后,下面為大家介紹位運(yùn)算符的兩種運(yùn)用場景几睛。

位運(yùn)算符的運(yùn)用

1房轿、取值

可以利用按位與 & 運(yùn)算取出指定位的值,具體操作是想取出哪一位的值就將那一位置為1,其它位都為0冀续,然后同原數(shù)據(jù)進(jìn)行按位與計(jì)算琼讽,即可取出特定的位。

例:0000 0011取出倒數(shù)第三位的值

// 想取出倒數(shù)第三位的值洪唐,就將倒數(shù)第三位的值置為1钻蹬,其它位為0,跟原數(shù)據(jù)按位與運(yùn)算
  0000 0011
& 0000 0100
------------
  0000 0000  // 得出按位與運(yùn)算后的結(jié)果凭需,即可拿到原數(shù)據(jù)中倒數(shù)第三位的值為0

上面的例子中问欠,我們從0000 0011中取值,則0000 0011被稱之為源碼粒蜈。進(jìn)行按位與操作設(shè)定的0000 0100稱之為掩碼

2顺献、設(shè)值

可以通過按位或 |運(yùn)算符將某一位的值設(shè)為1或0。具體操作是:
想將某一位的值置為1的話枯怖,那么就將掩碼中對應(yīng)位的值設(shè)為1注整,掩碼其它位為0,將源碼與掩碼進(jìn)行按位或操作即可度硝。

例:將0000 0011倒數(shù)第三位的值改為1

// 改變倒數(shù)第三位的值肿轨,就將掩碼倒數(shù)第三位的值置為1,其它位為0蕊程,跟源碼按位或運(yùn)算
  0000 0011
| 0000 0100
------------
  0000 0111  // 即可將源碼中倒數(shù)第三位的值改為1

想將某一位的值置為0的話椒袍,那么就將掩碼中對應(yīng)位的值設(shè)為0,掩碼其它位為1藻茂,將源碼與掩碼進(jìn)行按位或操作即可驹暑。

例:將0000 0011倒數(shù)第二位的值改為0

// 改變倒數(shù)第二位的值,就將掩碼倒數(shù)第二位的值置為0辨赐,其它位為1优俘,跟源碼按位或運(yùn)算
  0000 0011
| 1111 1101
------------
  0000 0001  // 即可將源碼中倒數(shù)第二位的值改為0

到這里相信大家對位運(yùn)算符有了一定的了解,下面我們通過OC代碼的一個(gè)例子掀序,來將位運(yùn)算符運(yùn)用到實(shí)際代碼開發(fā)中兼吓。

我們聲明一個(gè)Man類,類中有三個(gè)BOOL類型的屬性森枪,分別為tall视搏、richhandsome县袱,通過這三個(gè)屬性來判斷這個(gè)人是否高富帥浑娜。

Man類.png

然后我們查看一下一個(gè)Man類對象所占據(jù)的內(nèi)存大小:
Man類對象占據(jù)內(nèi)存.png

我們看到式散,一個(gè)Man類的對象占16個(gè)字節(jié)筋遭。其中包括一個(gè)isa指針和三個(gè)BOOL類型的屬性,8+1+1+1=11,根據(jù)內(nèi)存對齊原則所以一個(gè)Man類的對象占16個(gè)字節(jié)漓滔。

我們知道编饺,BOOL值只有兩種情況:01,占據(jù)一個(gè)字節(jié)的內(nèi)存空間响驴。而一個(gè)字節(jié)的內(nèi)存空間中又有8個(gè)二進(jìn)制位透且,并且二進(jìn)制同樣只有 01 ,那么我們完全可以使用1個(gè)二進(jìn)制位來表示一個(gè)BOOL值豁鲤。也就是說我們上面聲明的三個(gè)BOOL值最終只使用3個(gè)二進(jìn)制位就可以秽誊,這樣就節(jié)省了內(nèi)存空間。那我們?nèi)绾螌?shí)現(xiàn)呢琳骡?

想要實(shí)現(xiàn)三個(gè)BOOL值存放在一個(gè)字節(jié)中锅论,我們可以通過char類型的成員變量來實(shí)現(xiàn)。char類型占一個(gè)字節(jié)內(nèi)存空間楣号,也就是8個(gè)二進(jìn)制位最易。可以使用其中最后三個(gè)二進(jìn)制位來存儲3個(gè)BOOL值炫狱。

當(dāng)然我們不能把char類型寫成屬性藻懒,因?yàn)橐坏懗蓪傩裕到y(tǒng)會(huì)自動(dòng)幫我們添加成員變量毕荐,自動(dòng)實(shí)現(xiàn)setget方法束析。

@interface Man()
{
    char _tallRichHandsome;
}

如果我們賦值_tallRichHansome1艳馒,即0b 0000 0001 憎亚,只使用8個(gè)二進(jìn)制位中的最后3個(gè)分別用0或者1來代表tallrich弄慰、handsome的值第美。那么此時(shí)tallrich陆爽、handsome的狀態(tài)為:

char類型含義.png

結(jié)合我們上文將的6中位運(yùn)算符以及使用場景什往,我們可以分別聲明tallrich慌闭、handsome的掩碼别威,來方便我們進(jìn)行下一步的位運(yùn)算取值和賦值:

#define Tall_Mask 0b00000100 //此二進(jìn)制數(shù)對應(yīng)十進(jìn)制數(shù)為 4
#define Rich_Mask 0b00000010 //此二進(jìn)制數(shù)對應(yīng)十進(jìn)制數(shù)為 2
#define Handsome_Mask 0b00000001 //此二進(jìn)制數(shù)對應(yīng)十進(jìn)制數(shù)為 1

通過對位運(yùn)算符的左移 <<右移 >>的了解,我們可以將上面的代碼優(yōu)化成:

#define Tall_Mask (1<<2) // 0b00000100
#define Rich_Mask (1<<1) // 0b00000010
#define Handsome_Mask (1<<0) // 0b00000001

自定義的set方法如下:

- (void)setTall:(BOOL)tall
{
    if (tall) { // 如果需要將值置為1驴剔,將源碼和掩碼進(jìn)行按位或運(yùn)算
        _tallRichHandsome |= Tall_Mask;
    }else{ // 如果需要將值置為0 // 將源碼和按位取反后的掩碼進(jìn)行按位與運(yùn)算
        _tallRichHandsome &= ~Tall_Mask;
    }
}
- (void)setRich:(BOOL)rich
{
    if (rich) {
        _tallRichHandsome |= Rich_Mask;
    }else{
        _tallRichHandsome &= ~Rich_Mask;
    }
}
- (void)setHandsome:(BOOL)handsome
{
    if (handsome) {
        _tallRichHandsome |= Handsome_Mask;
    }else{
        _tallRichHandsome &= ~Handsome_Mask;
    }
}

自定義的get方法如下:

- (BOOL)isTall
{
    return !!(_tallRichHandsome & Tall_Mask);
}
- (BOOL)isRich
{
    return !!(_tallRichHandsome & Rich_Mask);
}
- (BOOL)isHandsome
{
    return !!(_tallRichHandsome & Handsome_Mask);
}

此處需要注意的是省古,代碼中!為邏輯運(yùn)算符,因?yàn)?code>_tallRichHandsome & Tall_Mask代碼執(zhí)行后丧失,返回的肯定是一個(gè)整型數(shù)豺妓,如當(dāng)tallYES時(shí),說明二進(jìn)制數(shù)為0b 0000 0100,對應(yīng)的十進(jìn)制數(shù)為4琳拭,那么進(jìn)行一次邏輯非運(yùn)算后训堆,!(4)的值為0,對0再進(jìn)行一次邏輯非運(yùn)算!(0)白嘁,結(jié)果就成了1坑鱼,那么正好跟tallYES對應(yīng)。所以此處進(jìn)行兩次邏輯非運(yùn)算权薯,!!姑躲。

當(dāng)然,還要實(shí)現(xiàn)初始化方法:

- (instancetype)init
{
    if (self = [super init]) {
        _tallRichHandsome = 0b00000100;
    }
    return self;
}

通過測試驗(yàn)證盟蚣,我們完成了取值和賦值:


測試代碼.png

使用結(jié)構(gòu)體位域優(yōu)化代碼

我們上文講到了位域的概念黍析,那么我們就可以使用結(jié)構(gòu)體位域來優(yōu)化一下我們的代碼。這樣就不用再額外聲明上面代碼中的掩碼部分屎开。位域聲明的格式是位域名 : 位域長度阐枣。
在使用位域的過程中需要注意以下幾點(diǎn):

1.如果一個(gè)字節(jié)所剩空間不夠存放另一位域時(shí)奄抽,應(yīng)從下一單元起存放該位域蔼两。
2.位域的長度不能大于數(shù)據(jù)類型本身的長度,比如int類型就不能超過32位二進(jìn)位逞度。
3.位域可以無位域名额划,這時(shí)它只用來作填充或調(diào)整位置。無名的位域是不能使用的档泽。

使用位域優(yōu)化以后:

使用位域優(yōu)化后的代碼.png

測試看一下是否正確俊戳,這次我們將tall設(shè)為YESrich設(shè)為NO馆匿、handsome設(shè)為YES
優(yōu)化后測試.png

依舊完成賦值和取值抑胎。
但是代碼這樣優(yōu)化后我們?nèi)サ袅搜诖a和初始化的代碼,可讀性很差渐北,我們繼續(xù)使用共用體進(jìn)行優(yōu)化:

使用共用體優(yōu)化代碼

我們可以使用比較高效的位運(yùn)算來進(jìn)行賦值和取值阿逃,使用union共用體來對數(shù)據(jù)進(jìn)行存儲。這樣不僅可以增加讀取效率赃蛛,還可以增強(qiáng)代碼可讀性恃锉。

#define Tall_Mask (1<<2) // 0b00000100
#define Rich_Mask (1<<1) // 0b00000010
#define Handsome_Mask (1<<0) // 0b00000001

@interface Man()
{
    union {
        char bits;
       // 結(jié)構(gòu)體僅僅是為了增強(qiáng)代碼可讀性
        struct {
            char tall : 1;
            char rich : 1;
            char handsome : 1;
        };
    }_tallRichHandsome;
}
@end

@implementation Man

- (void)setTall:(BOOL)tall
{
    if (tall) {
        _tallRichHandsome.bits |= Tall_Mask;
    }else{
        _tallRichHandsome.bits &= ~Tall_Mask;
    }
}
- (void)setRich:(BOOL)rich
{
    if (rich) {
        _tallRichHandsome.bits |= Rich_Mask;
    }else{
        _tallRichHandsome.bits &= ~Rich_Mask;
    }
}
- (void)setHandsome:(BOOL)handsome
{
    if (handsome) {
        _tallRichHandsome.bits |= Handsome_Mask;
    }else{
        _tallRichHandsome.bits &= ~Handsome_Mask;
    }
}
- (BOOL)isTall
{
    return !!(_tallRichHandsome.bits & Tall_Mask);
}
- (BOOL)isRich
{
    return !!(_tallRichHandsome.bits & Rich_Mask);
}
- (BOOL)isHandsome
{
    return !!(_tallRichHandsome.bits & Handsome_Mask);
}

其中_tallRichHandsome共用體只占用一個(gè)字節(jié),因?yàn)榻Y(jié)構(gòu)體中tall呕臂、rich破托、handsome都只占一位二進(jìn)制空間,所以結(jié)構(gòu)體只占一個(gè)字節(jié)诵闭,而char類型的bits也只占一個(gè)字節(jié)炼团,他們都在共用體中澎嚣,因此共用一個(gè)字節(jié)的內(nèi)存即可。
而且我們在set瘟芝、get方法中的賦值和取值通過使用掩碼進(jìn)行位運(yùn)算來增加效率易桃,整體邏輯也就很清晰了。

但是锌俱,如果我們在日常開發(fā)中這樣寫代碼的話晤郑,很可能會(huì)被同事打死。雖然代碼已經(jīng)很清晰了贸宏,但是整體閱讀起來很是很吃力的造寝。我們在這里學(xué)習(xí)位運(yùn)算以及共用體這些知識,更多的是為了方便我們閱讀OC底層的代碼吭练。下面我們就回到本文主題诫龙,查看一下isa_t共用體的源碼。

isa_t共用體

isa_t源碼.png

我們發(fā)現(xiàn)在isa_t共用體內(nèi)用宏ISA_BITFIELD定義了位域鲫咽,我們進(jìn)入位域內(nèi)查看源碼:
ISA_BITFIELD內(nèi)部源碼.png

我們看到屹篓,在內(nèi)部分別定義了arm64位架構(gòu)和x86_64架構(gòu)的掩碼和位域肚医。我們只分析arm64位架構(gòu)下的部分內(nèi)容(紅色標(biāo)注部分)轿腺。
可以清楚看到ISA_BITFIELD位域的內(nèi)容以及掩碼ISA_MASK的值:0x0000000ffffffff8ULL梗劫。
我們重點(diǎn)看一下uintptr_t shiftcls : 33;,在shiftcls中存儲著類對象和元類對象的內(nèi)存地址信息箩绍,我們上文講到孔庭,對象的isa指針需要同ISA_MASK經(jīng)過一次按位與運(yùn)算才能得出真正的類對象地址。那么我們將ISA_MASK的值0x0000000ffffffff8ULL轉(zhuǎn)化為二進(jìn)制數(shù)分析一下:
ISA_MASK轉(zhuǎn)化為二進(jìn)制.png

從圖中可以看到ISA_MASK的值轉(zhuǎn)化為二進(jìn)制中有33位都為1材蛛,上文講到按位與運(yùn)算是可以取出這33位中的值圆到。那么就說明同ISA_MASK進(jìn)行按位與運(yùn)算就可以取出類對象和元類對象的內(nèi)存地址信息。

我們繼續(xù)分析一下結(jié)構(gòu)體位域中其他的內(nèi)容代表的含義:

struct {
    // 0代表普通的指針仰税,存儲著類對象构资、元類對象的內(nèi)存地址抽诉。
    // 1代表優(yōu)化后的使用位域存儲更多的信息陨簇。
    uintptr_t nonpointer        : 1; 

   // 是否有設(shè)置過關(guān)聯(lián)對象,如果沒有迹淌,釋放時(shí)會(huì)更快
    uintptr_t has_assoc         : 1;

    // 是否有C++析構(gòu)函數(shù)河绽,如果沒有,釋放時(shí)會(huì)更快
    uintptr_t has_cxx_dtor      : 1;

    // 存儲著類對象唉窃、元類對象對象的內(nèi)存地址信息
    uintptr_t shiftcls          : 33; 

    // 用于在調(diào)試時(shí)分辨對象是否未完成初始化
    uintptr_t magic             : 6;

    // 是否有被弱引用指向過耙饰。
    uintptr_t weakly_referenced : 1;

    // 對象是否正在釋放
    uintptr_t deallocating      : 1;

    // 引用計(jì)數(shù)器是否過大無法存儲在isa中
    // 如果為1,那么引用計(jì)數(shù)會(huì)存儲在一個(gè)叫SideTable的類的屬性中
    uintptr_t has_sidetable_rc  : 1;

    // 里面存儲的值是引用計(jì)數(shù)器減1
    uintptr_t extra_rc          : 19;
};

至此我們已經(jīng)對isa指針有了新的認(rèn)識纹份,__arm64__架構(gòu)之后苟跪,isa指針不單單只存儲了類對象和元類對象的內(nèi)存地址廷痘,而是使用共用體的方式存儲了更多信息,其中shiftcls存儲了類對象和元類對象的內(nèi)存地址件已,需要同ISA_MASK進(jìn)行按位與 &運(yùn)算才可以取出其內(nèi)存地址值笋额。

更多技術(shù)知識請關(guān)注公眾號
iOS進(jìn)階


iOS進(jìn)階.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市篷扩,隨后出現(xiàn)的幾起案子兄猩,更是在濱河造成了極大的恐慌,老刑警劉巖鉴未,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枢冤,死亡現(xiàn)場離奇詭異,居然都是意外死亡铜秆,警方通過查閱死者的電腦和手機(jī)淹真,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來连茧,“玉大人趟咆,你說我怎么就攤上這事∶诽耄” “怎么了值纱?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坯汤。 經(jīng)常有香客問我虐唠,道長,這世上最難降的妖魔是什么惰聂? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任疆偿,我火速辦了婚禮,結(jié)果婚禮上搓幌,老公的妹妹穿的比我還像新娘杆故。我一直安慰自己,他們只是感情好溉愁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布处铛。 她就那樣靜靜地躺著,像睡著了一般拐揭。 火紅的嫁衣襯著肌膚如雪撤蟆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天堂污,我揣著相機(jī)與錄音家肯,去河邊找鬼。 笑死盟猖,一個(gè)胖子當(dāng)著我的面吹牛讨衣,可吹牛的內(nèi)容都是我干的换棚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼反镇,長吁一口氣:“原來是場噩夢啊……” “哼圃泡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起愿险,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤颇蜡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后辆亏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體风秤,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年扮叨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缤弦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彻磁,死狀恐怖碍沐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衷蜓,我是刑警寧澤累提,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站磁浇,受9級特大地震影響斋陪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜置吓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一无虚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衍锚,春花似錦友题、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至置森,卻和暖如春斗埂,著一層夾襖步出監(jiān)牢的瞬間符糊,已是汗流浹背凫海。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留男娄,地道東北人行贪。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓漾稀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親建瘫。 傳聞我的和親對象是個(gè)殘疾皇子崭捍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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