Block 深入研究

Block的本質(zhì)

Block本質(zhì)上也是一個(gè)OC對(duì)象定页,它的內(nèi)部有一個(gè)isa指針剃法,block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的oc對(duì)象

首先巾兆,我們利用clang 命令查看一下聲明Block對(duì)應(yīng)的c++代碼(

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m

)main.m 是文件名

image.png

轉(zhuǎn)換為C++

image.png

block 聲明刪減一部分轉(zhuǎn)化代碼嗓袱,如下

image.png

查找轉(zhuǎn)換后的C++代碼,其實(shí)block是有結(jié)構(gòu)體組成的,具體形式如下:

image.png

也可以理解為

image.png

因此赵讯,這個(gè)block結(jié)構(gòu)體 包含了isa 指針

再查找 __main_block_impl_0 函數(shù)

  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) :                       age(_age) {

    impl.isa = &_NSConcreteStackBlock;

    impl.Flags = flags;

    impl.FuncPtr = fp;

    Desc = desc;

  }

block實(shí)現(xiàn)的函數(shù) 的isa 指向_NSConcreteStackBlock 對(duì)象盈咳,因此說(shuō)明block 是oc對(duì)象

我們還可以自定義block結(jié)構(gòu)體耿眉,用于探測(cè)block 內(nèi)部實(shí)現(xiàn)過(guò)程

struct __main_block_desc_0 {

    size_t reserved;

    size_t Block_size;

};

struct __block_impl {

    void *isa;

    int Flags;

    int Reserved;

    void *FuncPtr;

};

struct __main_block_impl_0 {

    struct __block_impl impl;

    struct __main_block_desc_0* Desc;

    int age;

};

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        int age = 20;

        void (^block)(int, int) =  ^(int a , int b){

            NSLog(@"this is a block! -- %d", age);

            NSLog(@"this is a block!");

        };

        struct __main_block_impl_0 *blockStruct = (__bridge struct __main_block_impl_0 *)block;

         block(10, 10);

    }

    return 0;

}
image.png

為什么block內(nèi)部修改變量沒(méi)有效果

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        int age = 10;

       void (^block)(void) = ^{

            // age的值捕獲進(jìn)來(lái)(capture)

            NSLog(@"age is %d", age);

        };

        age = 20;

        block();

    }

    return 0;

}

為什么age的值被修改了,但是打印得到的是修改之前的值呢鱼响?

沒(méi)有其他參考途徑鸣剪,我們只有接著cpp文件

//相當(dāng)于OC對(duì)象

struct __main_block_impl_0 {

  struct __block_impl impl;

  struct __main_block_desc_0* Desc;

  int age;

    //相當(dāng)于OC 構(gòu)造函數(shù)

  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {

    impl.isa = &_NSConcreteStackBlock;

    impl.Flags = flags;

    impl.FuncPtr = fp;

    Desc = desc;

    // age(_age) 相當(dāng)于 把_age的值賦給age 此時(shí)所生成的block對(duì)象中的age的值就是_age,也就是傳遞過(guò)來(lái)的10

  }

};

int main(int argc, const char * argv[]) {

    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;

        int age = 10;

        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));

        //相當(dāng)于調(diào)用了__main_block_impl_0函數(shù),并把a(bǔ)ge這個(gè)變量的值傳遞了過(guò)去丈积,

//        void (*block)(void) = &__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, age);

        age = 20;

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

    }

    return 0;

}

//因此在blcok 外部改變變量的值  block內(nèi)部并沒(méi)有發(fā)生改變

為什么 static 修飾的變量可以更改值

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        int age = 10;

        static int height = 10;

        void (^block)(void) = ^{

            // age的值捕獲進(jìn)來(lái)(capture)

            NSLog(@"age is %d, height is %d", age, height);

        };

        age = 20;

        height = 20;

        block();

    }

    return 0;

}

//c++ 

int main(int argc, const char * argv[]) {

    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;

        int age = 10;

        static int height = 10;

        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age, &height));

        age = 20;

        height = 20;

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

    }

    return 0;

}

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

  int age = __cself->age; // bound by copy

  int *height = __cself->height; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_4z_4p5xc0z55l38rrjdfyrzdxbw0000gn_T_main_2d6064_mi_1, age, (*height));

}

通過(guò)以上代碼筐骇,我們發(fā)現(xiàn)static 修飾的變量傳遞的是地址,在block內(nèi)部函數(shù)也訪問(wèn)的是(*height)而沒(méi)static修飾的age則直接訪問(wèn)的是變量

為什么static 修飾就傳遞地址呢江滨? 因?yàn)閟tatic修飾的變量 屬于靜態(tài)變量铛纬,首次被加載時(shí)static定義的變量被分配空間,程序結(jié)束后由系統(tǒng)釋放.所以它在內(nèi)存中是一直存在的,而被修飾的變量唬滑,在一定條件下是會(huì)被釋放的告唆,這是系統(tǒng)為了保持正確性,就把它的值傳遞過(guò)去晶密。

放上一個(gè)別人總結(jié)的圖擒悬,我覺(jué)得他能把上面的意思完全概括:

image.png

block的類型

前面說(shuō)過(guò)block是oc對(duì)象,所以我們可以調(diào)用oc方法來(lái)查看它的父類稻艰,以及父類的父類

        void (^block)(void) = ^{

            NSLog(@"Hello");

        };

        NSLog(@"%@", [block class]);//__NSGlobalBlock__

        NSLog(@"%@", [[block class] superclass]);//__NSGlobalBlock

        NSLog(@"%@", [[[block class] superclass] superclass]);//NSBlock

        NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);//NSObject

所以很好的證明了block是OC對(duì)象懂牧。

但是在不同環(huán)境下,block的類型是不同的

*   block有3種類型尊勿,可以通過(guò)調(diào)用class方法或者isa指針查看具體類型僧凤,最終都是繼承自NSBlock類型

*   __NSGlobalBlock__( _NSConcreteGlobalBlock)

*   __NSStackBlock__( _NSConcreteStackBlock )

*   __NSMallocBlock__( _NSConcreteMallocBlock )

        void (^block1)(void) = ^{

            NSLog(@"Hello");

        };

        int age = 10;

        void (^block2)(void) = ^{

            NSLog(@"Hello - %d", age);

        };

        NSLog(@"%@ %@ %@", [block1 class], [block2 class], [^{

            NSLog(@"%d", age);  //__NSGlobalBlock__ __NSMallocBlock__ __NSStackBlock__

        } class]);
image.png
image.png

何為auto變量?

其實(shí)我們?cè)诙x局部變量時(shí)元扔,系統(tǒng)會(huì)默認(rèn)的添加 auto 關(guān)鍵字

 //  特別注意是在MRC環(huán)境下躯保,因?yàn)锳RC環(huán)境,運(yùn)行時(shí)會(huì)做一系列的操作

// Global:沒(méi)有訪問(wèn)auto變量 

    void (^block1)(void) = ^{

        NSLog(@"block1---------");

    };

    // Stack:訪問(wèn)了auto變量

    int age = 10; // 相當(dāng)于 auto int age = 10;

    void (^block2)(void) = ^{

        NSLog(@"block2---------%d", age);

    };

    NSLog(@"%@ %@", [block1 class], [block2 class]);//__NSGlobalBlock__ __NSStackBlock__

Block內(nèi)部實(shí)現(xiàn)中(static struct __main_block_desc_0)的兩種形態(tài)

第1種

static struct __main_block_desc_0 {

    size_t reserved;

    size_t Block_size;

};

**第二種**

static struct __main_block_desc_0 {

  size_t reserved;

  size_t Block_size;

  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);

  void (*dispose)(struct __main_block_impl_0*);

} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

相比較兩種 __main_block_desc_0 會(huì)發(fā)現(xiàn) 第二種(__main_block_desc_0)多出來(lái)兩個(gè)函數(shù)(copy摇展,dispose)吻氧,這是因?yàn)樵赽lock引用對(duì)象變量才會(huì)出現(xiàn)第二種情況(因?yàn)橐脤?duì)象變量時(shí),要涉及內(nèi)存管理咏连,要確保使用的對(duì)象不會(huì)出現(xiàn)內(nèi)存問(wèn)題盯孙,因此block內(nèi)部也會(huì)對(duì)其使用的對(duì)象做【return/release】)

block的copy

在ARC環(huán)境下,編譯器會(huì)根據(jù)情況自動(dòng)將棧上的block復(fù)制到堆上祟滴,比如以下情況

block作為函數(shù)返回值時(shí)

將block賦值給__strong指針時(shí)

block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)

block作為GCD API的方法參數(shù)時(shí)

如果block被拷貝到堆上

1振惰、會(huì)調(diào)用block內(nèi)部的copy函數(shù)

2、copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)

3垄懂、_Block_object_assign函數(shù)會(huì)根據(jù)變量的修飾符(__strong骑晶、__weak痛垛、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(return)或弱引用

 block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, 570425344));

//__main_block_desc_0  相比較之前沒(méi)有強(qiáng)弱引用變量時(shí)桶蛔,多出來(lái)copy  dispose 函數(shù)

static struct __main_block_desc_0 {

  size_t reserved;

  size_t Block_size;

  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);

  void (*dispose)(struct __main_block_impl_0*);

} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}

如果block從堆上移除

1匙头、會(huì)調(diào)用block內(nèi)部的dispose函數(shù)

2、dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)

3仔雷、_Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的變量(release)

image.png

__block修飾符

有時(shí)候我們要在block 中修改block之外的變量值蹂析,可以用static修改此變量,也可以設(shè)置為全局變量碟婆,但是我們有時(shí)只是臨時(shí)用下此變量电抚,沒(méi)有必要做如此復(fù)雜的操作

__block可以用于解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題

__block不能修飾全局變量、靜態(tài)變量(static)

編譯器會(huì)將__block變量包裝成一個(gè)對(duì)象

(分別討論一下(基本數(shù)據(jù)類型) int 和 對(duì)象的區(qū)別)

我們都知道__block修飾的變量 可以再block內(nèi)部對(duì)他進(jìn)行修改竖共,但這是為什么呢蝙叛?

__block修飾的變量會(huì)在運(yùn)行時(shí),由系統(tǒng)封裝成為 (Block_byref變量名序號(hào))結(jié)構(gòu)體類型的對(duì)象公给,我們?cè)赽lock內(nèi)部和之后訪問(wèn)的變量 都是轉(zhuǎn)換過(guò)后的類型

   __block int age = 10;

//        __attribute__((__blocks__(byref))) __Block_byref_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 10};

        __block NSObject *obj = [NSObject new];

       //        __attribute__((__blocks__(byref))) __Block_byref_obj_1 obj = {(void*)0,(__Block_byref_obj_1 *)&obj, 33554432, sizeof(__Block_byref_obj_1), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("new"))};

        HFBlock block = ^{

            age = 20;

            obj = nil;

//  __Block_byref_age_0 *age = __cself->age; // bound by ref

//  __Block_byref_obj_1 *obj = __cself->obj; // bound by ref

//

//            (age->__forwarding->age) = 20;

//            (obj->__forwarding->obj) = __null;

            NSLog(@"age is %d", age);

        };

        NSLog(@"%p", &age);//對(duì)應(yīng)轉(zhuǎn)換后   

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_4z_4p5xc0z55l38rrjdfyrzdxbw0000gn_T_main_218c5b_mi_1, &(age.__forwarding->age));   我們確定他訪問(wèn)的是對(duì)象中的age

轉(zhuǎn)換后

struct __Block_byref_age_0 {

  void *__isa;

__Block_byref_age_0 *__forwarding;

 int __flags;

 int __size;

 int age;

};

struct __Block_byref_obj_1 {

  void *__isa;

__Block_byref_obj_1 *__forwarding;

 int __flags;

 int __size;

 void (*__Block_byref_id_object_copy)(void*, void*);

 void (*__Block_byref_id_object_dispose)(void*);

 NSObject *__strong obj;

};

通過(guò)上述代碼我們得出結(jié)論借帘,變量在聲明__block后 就會(huì)轉(zhuǎn)為其他對(duì)象形式,并且在聲明以后用到的次變量都是__Block_byref _ 變量名 _序號(hào) 類型的

相比較基本數(shù)據(jù)類型轉(zhuǎn)換的類型妓布,對(duì)象類型的屬性轉(zhuǎn)換后姻蚓,會(huì)多出來(lái)(__Block_byref_id_object_copy,__Block_byref_id_object_dispose)兩個(gè)函數(shù)匣沼,這是因?yàn)檎玻瑢?duì)象類型要涉及到內(nèi)存管理,這兩個(gè)函數(shù)是內(nèi)存管理所用到的

為了從內(nèi)存地址角度證明 我們?cè)赽lock外訪問(wèn)的變量也是轉(zhuǎn)換過(guò)的類型释涛,

typedef void (^HFBlock) (void);

struct __Block_byref_age_0 {

    void *__isa;

    struct __Block_byref_age_0 *__forwarding;

    int __flags;

    int __size;

    int age;

};

struct __main_block_desc_0 {

    size_t reserved;

    size_t Block_size;

    void (*copy)(void);

    void (*dispose)(void);

};

struct __block_impl {

    void *isa;

    int Flags;

    int Reserved;

    void *FuncPtr;

};

struct __main_block_impl_0 {

    struct __block_impl impl;

    struct __main_block_desc_0* Desc;

    struct __Block_byref_age_0 *age;

};

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        __block int age = 10;

        __block NSObject *obj = [NSObject new];

        HFBlock block = ^{

            age = 20;

            obj = nil;

            NSLog(@"age is %d", age);

        };

        struct __main_block_impl_0 *blockImpl = (__bridge struct __main_block_impl_0 *)block;

        NSLog(@"%p", &age);//0x100425288

    }

    return 0;

}

我們需按照cpp代碼的思路自定義幾個(gè)機(jī)構(gòu)體加叁,來(lái)強(qiáng)制轉(zhuǎn)換以此來(lái)窺看系統(tǒng)內(nèi)部的操作,

(lldb) p/x blockImpl->age

(__Block_byref_age_0 *) $4 = 0x0000000100425270

(lldb) p/x &(blockImpl->age->age)

(int *) $5 = 0x0000000100425288

由此我們看到唇撬,block中age對(duì)象 距離訪問(wèn)的age的值 相差24個(gè)字節(jié)它匕,我們?cè)倏碼ge結(jié)構(gòu)體

struct __Block_byref_age_0 {//假設(shè)這個(gè)對(duì)象的內(nèi)存地址是0x0000000100425270

    void *__isa;//指針8個(gè)字節(jié)

    struct __Block_byref_age_0 *__forwarding;//指針8個(gè)字節(jié)

    int __flags;//4個(gè)字節(jié)

    int __size;//4個(gè)字節(jié)

    //age 的地址是 0x0000000100425270 + 8 + 8 + 4 + 4  = 0x0000000100425288

    int age;

};

這和我們的打印結(jié)果完全吻合,由此再次得到證明

__block的內(nèi)存管理

當(dāng)block在棧上時(shí)窖认,并不會(huì)對(duì)__block變量產(chǎn)生強(qiáng)引用

  • 當(dāng)block被copy到堆時(shí)

  • 會(huì)調(diào)用block內(nèi)部的copy函數(shù)

  • copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)

  • _Block_object_assign函數(shù)會(huì)對(duì)__block變量形成強(qiáng)引用(retain)

當(dāng)block從堆中移除時(shí)

  • 會(huì)調(diào)用block內(nèi)部的dispose函數(shù)

  • dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)

  • _Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的__block變量(release)

對(duì)象類型的auto變量豫柬、__block變量

當(dāng)block在棧上時(shí),對(duì)它們都不會(huì)產(chǎn)生強(qiáng)引用

當(dāng)block拷貝到堆上時(shí)扑浸,都會(huì)通過(guò)copy函數(shù)來(lái)處理它們

  • __block變量(假設(shè)變量名叫做a)

  • _Block_object_assign((void)&dst->a, (void)src->a, 8/BLOCK_FIELD_IS_BYREF/);

  • 對(duì)象類型的auto變量(假設(shè)變量名叫做p)

  • _Block_object_assign((void)&dst->p, (void)src->p, 3/BLOCK_FIELD_IS_OBJECT/);

當(dāng)block從堆上移除時(shí)烧给,都會(huì)通過(guò)dispose函數(shù)來(lái)釋放它們

  • __block變量(假設(shè)變量名叫做a)

  • _Block_object_dispose((void)src->a, 8/BLOCK_FIELD_IS_BYREF*/);

  • 對(duì)象類型的auto變量(假設(shè)變量名叫做p)

  • _Block_object_dispose((void)src->p, 3/BLOCK_FIELD_IS_OBJECT*/);

被__block修飾的對(duì)象類型

  • 當(dāng)__block變量在棧上時(shí),不會(huì)對(duì)指向的對(duì)象產(chǎn)生強(qiáng)引用

  • 當(dāng)__block變量被copy到堆時(shí)

  • 會(huì)調(diào)用__block變量?jī)?nèi)部的copy函數(shù)

  • copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)

  • _Block_object_assign函數(shù)會(huì)根據(jù)所指向?qū)ο蟮男揎椃╛_strong喝噪、__weak础嫡、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用(注意:這里僅限于ARC時(shí)會(huì)retain酝惧,MRC時(shí)不會(huì)retain)

  • 如果__block變量從堆上移除

  • 會(huì)調(diào)用__block變量?jī)?nèi)部的dispose函數(shù)

  • dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)

  • _Block_object_dispose函數(shù)會(huì)自動(dòng)釋放指向的對(duì)象(release)

__block的__forwarding指針

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末榴鼎,一起剝皮案震驚了整個(gè)濱河市伯诬,隨后出現(xiàn)的幾起案子巫财,更是在濱河造成了極大的恐慌,老刑警劉巖翁涤,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異葵礼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)并鸵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)园担,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)届谈,“玉大人,你說(shuō)我怎么就攤上這事弯汰〖枭剑” “怎么了咏闪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鸽嫂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我据某,道長(zhǎng),這世上最難降的妖魔是什么挽唉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任筷狼,我火速辦了婚禮,結(jié)果婚禮上棘劣,老公的妹妹穿的比我還像新娘楞遏。我一直安慰自己首昔,他們只是感情好糙俗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布巧骚。 她就那樣靜靜地躺著,像睡著了一般劈彪。 火紅的嫁衣襯著肌膚如雪沧奴。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天纲菌,我揣著相機(jī)與錄音疮绷,去河邊找鬼。 笑死冬骚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的夜涕。 我是一名探鬼主播属愤,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼驾胆!你這毒婦竟也來(lái)了贱呐?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤驳阎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后呵晚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體饵隙,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年芯急,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驶俊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伺绽,死狀恐怖嗜湃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肩榕,我是刑警寧澤株汉,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蝙云,受9級(jí)特大地震影響路召,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜身隐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一唯灵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垢揩,春花似錦、人聲如沸镰矿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苍姜。三九已至悬包,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間布近,已是汗流浹背撑瞧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留订咸,地道東北人酬诀。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像父叙,于是被迫代替她去往敵國(guó)和親葵腹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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