iOS Block存儲域及循環(huán)引用

系列文章:
iOS Block概念、語法及基本使用
iOS Block實現(xiàn)原理
iOS Block __block說明符

本文將講解以下幾點:

  • Block種類
  • Block變量存儲域
  • __block變量存儲域
  • 截獲對象
  • __block變量和對象
  • Block循環(huán)引用

根據(jù)上幾篇文章Block語法編譯后的源代碼我們看到,__block_impl結(jié)構(gòu)體內(nèi)部有一個成員變量:isa指針兰迫,__main_block_impl_0結(jié)構(gòu)體初始化的時候沼填,isa指針初始化為 impl.isa = &_NSConcreteStackBlock吮播,因為Block也是OC對象挖藏,我們說該isa指針指向該Block實例所屬的Block類最楷。

Block種類

Block有以下幾種:

Block 類 Block存儲域
_NSConcreteStackBlock
_NSConcreteGlobalBlock 程序的數(shù)據(jù)區(qū)域(.data 區(qū))
_NSConcreteMallocBlock

順便說一下程序的內(nèi)存分配情況:

區(qū)域 存放的東東
棧區(qū)(stack) 由編譯器自動分配釋放 循衰,存放函數(shù)的參數(shù)值铲敛,局部變量的值
堆區(qū)(heap) 程序員分配(alloc/new/copy/mutableCopy)
全局區(qū)(靜態(tài)區(qū))static 全局變量和靜態(tài)變量
常量區(qū) 常量字符串等
數(shù)據(jù)區(qū)(代碼區(qū)) 存放函數(shù)體的二進(jìn)制代碼

到目前位置看到的Block全都是_NSConcreteStackBlock,其實不是這樣的会钝,在記述全局變量的地方使用Block語法時伐蒋,生成的Block為 _NSConcreteGlobalBlock,舉個例子看下:

@implementation ViewController

void (^block)(void) = ^{
    NSLog(@"haha");
};

@end

編譯后__block_block_impl_0結(jié)構(gòu)體:

struct __block_block_impl_0 {
  struct __block_impl impl;
  struct __block_block_desc_0* Desc;
  __block_block_impl_0(void *fp, struct __block_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteGlobalBlock;//global
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

該Block的類為_NSConcreteGlobalBlock類迁酸,即存放在數(shù)據(jù)區(qū)也就是代碼區(qū)先鱼,因為使用全局變量的地方不能使用自動變量,所以不存在對自動變量的截獲奸鬓。由此Block結(jié)構(gòu)體實例的內(nèi)容不依賴于執(zhí)行的狀態(tài)焙畔,所以整個程序中只需一個實例,因此把該結(jié)構(gòu)體實例放在數(shù)據(jù)區(qū)串远。

在以下情況下生成的Block結(jié)構(gòu)體實例屬于 _NSConcreteGlobalBlock類:

  1. 記述全局變量的地方有Block語法時宏多;
  2. Block語法的表達(dá)式中不使用截獲的自動變量時儿惫;

除以上兩種情況外,都會生成 _NSConcreteStackBlock類伸但,且保存在棧區(qū)域肾请。

一、Block變量存儲域

配置在全局變量上的Block更胖,從變量作用域外也可以通過指針安全地使用铛铁,但是設(shè)置在棧的Block,如果其所屬的變量作用域結(jié)束函喉,該block也就被廢棄避归。由于__block變量也配置在棧上,同樣其所屬的變量作用域結(jié)束管呵,則該__block變量也同樣被廢棄梳毙。
Block提供了將Block從棧區(qū)copy到堆區(qū)的方法。如下圖:


復(fù)制到堆上.jpg

復(fù)制到堆上的Block將_NSConcreteMallocBlock類對象寫入Block結(jié)構(gòu)體實例的成員變量isa:

impl.isa = &_NSConcreteMallocBlock;

還記得上一節(jié)說到的__block變量結(jié)構(gòu)體實例的 __forwarding 指針指向__block變量結(jié)構(gòu)體自己吧捐下,也就是說無論Block結(jié)構(gòu)體實例配置在棧上還是堆上账锹,都能夠訪問__block變量。

那么什么時候Block從棧上復(fù)制到堆上呢坷襟,其實大多數(shù)情況下奸柬,編譯器會恰當(dāng)?shù)倪M(jìn)行判斷,自動生成將Block從棧上復(fù)制到堆上婴程。

以下情況需要程序員自己通過copy方法將Block從棧區(qū)復(fù)制到堆區(qū):

  1. 向方法或函數(shù)的參數(shù)中傳遞Block時廓奕;

不需要手動復(fù)制的情況:

  1. Cocoa框架的方法且方法名中含有usingBlock等時;
  2. GCD的API

下圖是按Block的存儲域档叔,使用copy后桌粉,Block有什么變化

Block的類 Block原區(qū)域 復(fù)制后
_NSConcreteStackBlock 從棧復(fù)制到堆
_NSConcreteGlobalBlock 數(shù)據(jù)區(qū) 什么也不做
_NSConcreteMallocBlock 引用計數(shù)增加

從從上邊可以看出,不管Block配置在何處衙四,用copy方法復(fù)制都不會出現(xiàn)任何問題铃肯。在不確定時調(diào)用copy方法即可。
此處有一個例子:

blk = [[[[blk copy] copy] copy] copy];

該代碼解釋如下:

{
    //將配置在堆上的Block復(fù)制給變量tmp传蹈,變量tmp持有強(qiáng)引用的Block押逼;
    blk_t tmp = [blk copy];
    //將Block變量tmp賦值給blk變量,大括號走完后惦界,tmp釋放挑格,blk繼續(xù)持有Block;
    blk = tmp;
}
//以此類推...
{
    blk_t tmp = [blk copy];
    blk = tmp;
}
{
    blk_t tmp = [blk copy];
    blk = tmp;
}
{
    blk_t tmp = [blk copy];
    blk = tmp;
}

由此可見沾歪,ARC下使用copy完全沒問題漂彤。

二、__block變量存儲域

Block從棧上復(fù)制到堆上,那么在Block中使用的__block變量是怎么處理的呢,看下表:

__block變量配置區(qū)域 Block從棧復(fù)制到堆時的影響
從棧復(fù)制到堆并被Block持有
被Block持有

說明:若一個Block中使用了__block變量显歧,當(dāng)Block變量從棧復(fù)制到堆上時仪或,那么__block變量也會被復(fù)制到堆上。


__block變量復(fù)制到堆上.jpg

多個Block變量使用__block變量時,因為最先會將所有的Block配置在棧上士骤,所以__block變量也會配置在棧上范删。在任何一個Block變量被賦值到堆上時,__block變量一并被賦值到堆上拷肌,當(dāng)其他的Block變量復(fù)制到堆上時到旦,其使用的__block變量引用計數(shù)增加:


__block變量被復(fù)制到堆區(qū).jpg

配置在堆上的Block被廢棄時,__block變量也被廢棄:


__block變量廢棄.jpg

到這里我們看到巨缘,Block變量和OC對象的內(nèi)存管理機(jī)制是一樣的添忘,都是使用引用計數(shù),所以也驗證了那句話:Block是OC對象若锁。

三搁骑、截獲對象

先來看一個例子:

typedef void (^block)(id obj);

block blk;//全局變量Block

- (void)viewDidLoad {
    [super viewDidLoad];
 
    id array = [NSMutableArray array];
    blk = [^(id obj){
        [array addObject:obj];
        NSLog(@"array count = %ld",[array count]);
    } copy];
    blk([[NSObject alloc] init]);
    blk([[NSObject alloc] init]);
    blk([[NSObject alloc] init]);
}

打印:

array count = 1
array count = 2
array count = 3

從源代碼可以看出又固,array變量是臨時變量仲器,viewDidLoad方法走完就被廢棄,但依然有打印仰冠,說明變量沒有釋放乏冀,從前幾篇文章可以想象,打印的array變量被Block結(jié)構(gòu)體實例持有了洋只,下面來驗證下辆沦,編譯后的代碼如下:

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

static struct __ViewController__viewDidLoad_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __ViewController__viewDidLoad_block_impl_0*, struct __ViewController__viewDidLoad_block_impl_0*);
  void (*dispose)(struct __ViewController__viewDidLoad_block_impl_0*);
} __ViewController__viewDidLoad_block_desc_0_DATA = {
    0,
    sizeof(struct __ViewController__viewDidLoad_block_impl_0),
    __ViewController__viewDidLoad_block_copy_0,
    __ViewController__viewDidLoad_block_dispose_0
};

//函數(shù)指針調(diào)用的函數(shù)
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself, id obj) {
  id array = __cself->array; // bound by copy
        ((void (*)(id, SEL, ObjectType _Nonnull))(void *)objc_msgSend)((id)array, sel_registerName("addObject:"), (id)obj);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_9k_z85dfkt91zd1j387gcxn8xkh0000gn_T_ViewController_503b9f_mi_0,((NSUInteger (*)(id, SEL))(void *)objc_msgSend)((id)array, sel_registerName("count")));
    }

//copy 和 dispose 函數(shù)
static void __ViewController__viewDidLoad_block_copy_0(struct __ViewController__viewDidLoad_block_impl_0*dst, struct __ViewController__viewDidLoad_block_impl_0*src) {_Block_object_assign((void*)&dst->array, (void*)src->array, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __ViewController__viewDidLoad_block_dispose_0(struct __ViewController__viewDidLoad_block_impl_0*src) {_Block_object_dispose((void*)src->array, 3/*BLOCK_FIELD_IS_OBJECT*/);}

//Block結(jié)構(gòu)體
struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl;
  struct __ViewController__viewDidLoad_block_desc_0* Desc;
  id array;//持有array變量
  __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, id _array, int flags=0) : array(_array) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

//viewDidLoad 方法
static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));

    id array = ((NSMutableArray * _Nonnull (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("array"));
    blk = (block)((id (*)(id, SEL))(void *)objc_msgSend)((id)((void (*)(id))&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, array, 570425344)), sel_registerName("copy"));
    
    ((void (*)(__block_impl *, id))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk, ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init")));
    
    ((void (*)(__block_impl *, id))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk, ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init")));
    
    ((void (*)(__block_impl *, id))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk, ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init")));
}

請注意,可以看到识虚,id 類型的 array變量被Block結(jié)構(gòu)體持有了肢扯。
在這里說明一點,其實我們創(chuàng)建的對象舷礼,默認(rèn)會帶上__strong所有權(quán)修飾符鹃彻,比如:

id array = [NSMutableArray array];

上邊代碼等同于下邊代碼:

id __strong array = [NSMutableArray array];

在OC語言中郊闯,C語言的結(jié)構(gòu)體不能含有附有__strong修飾符的變量妻献,因為編譯器不知道應(yīng)何時進(jìn)行C語言結(jié)構(gòu)體的初始化和廢棄操作,不能很好的管理內(nèi)存团赁。

前兩節(jié)我們看到了copy dispose 函數(shù)育拨,沒有做詳細(xì)解釋,只是猜想了一下欢摄,接下來說說這兩個函數(shù)熬丧。

OC運(yùn)行時可以準(zhǔn)確的把握block從棧上復(fù)制到堆上和Block廢棄的時機(jī),因此Block結(jié)構(gòu)體內(nèi)部使用帶有__strong或__weak修飾符的變量怀挠,也可以在恰當(dāng)?shù)臅r刻初始化和廢棄析蝴,為此需要在 __ViewController__viewDidLoad_block_desc_0 結(jié)構(gòu)體內(nèi)部加上 copy 和 dispose 成員變量害捕,以及作為函數(shù)指針賦值給這兩個變量的 __ViewController__viewDidLoad_block_copy_0 和 __ViewController__viewDidLoad_block_dispose_0函數(shù)

copy函數(shù)內(nèi)部使用了_Block_object_assign函數(shù)將對象類型對象賦值給Block結(jié)構(gòu)體內(nèi)的成員變量并持有該對象。_Block_object_assign函數(shù)調(diào)用相當(dāng)于retain實例方法的函數(shù)闷畸。

dispose函數(shù)內(nèi)部使用_Block_object_dispose函數(shù)釋放Block結(jié)構(gòu)體內(nèi)部的對象類型的成員變量尝盼。_Block_object_dispose函數(shù)調(diào)用相當(dāng)于release實例方法的函數(shù)。

我們只看到了生成的copy和dispose函數(shù)佑菩,但是沒看到調(diào)用啊盾沫,那到底啥時候調(diào)用這兩個函數(shù)呢,這是系統(tǒng)自動發(fā)生的動作:

函數(shù) 調(diào)用時機(jī)
copy 棧上Block被復(fù)制到堆上時
dispose 堆上Block被廢棄時

當(dāng)Block從棧上復(fù)制到堆上時殿漠,會調(diào)用copy函數(shù)赴精;當(dāng)堆上的Block被廢棄時,會調(diào)用dispose函數(shù)绞幌。

上一節(jié)提到了兩點蕾哟,什么時候block會從棧上復(fù)制到堆上,現(xiàn)在總結(jié)如下:

  • Block調(diào)用copy方法時
  • Block作為函數(shù)返回值返回時
  • 將Block賦值給賦有__strong修飾符id類型的類或Block類型成員變量時
  • 在方法名中含有usingBlock的Cocoa框架方法或GCD的API中傳遞Block時

有了這種構(gòu)造莲蜘,通過使用__strong修飾符的變量渐苏,Block中截獲的對象就能超出其變量作用域存在。

上一節(jié)我們研究__block變量的時候菇夸,看到過copy 和 dispose函數(shù)琼富,現(xiàn)在Block截獲對象的也出現(xiàn)了,而且轉(zhuǎn)換后的代碼基本相同庄新,后邊的注釋不同:

類型 _Block_object_assign/dispose函數(shù)
Block截獲對象 BLOCK_FIELD_IS_OBJECT
__block變量 BLOCK_FIELD_IS_BYREF

通過這兩個OBJECT鞠眉、BYREF來區(qū)分copy/dispose函數(shù)的對象類型是對象還是__block變量。與copy函數(shù)持有截獲的對象择诈,dispose釋放持有的對象相同械蹋,copy函數(shù)持有Block所使用的__block變量,dispose函數(shù)釋放__block變量羞芍。

有一點需要說明哗戈,這本書上的截獲對象的例子,Block不調(diào)用copy方法荷科,我本地測試的不會強(qiáng)制結(jié)束唯咬。可以解釋為:blk變量為全局變量畏浆,生成的Block結(jié)構(gòu)體實例也是全局變量胆胰,全局變量持有array變量,所以程序不會強(qiáng)制結(jié)束刻获。如果這個解釋有誤的話蜀涨,還請讀者指正,謝!

四厚柳、__block變量和對象

__block說明符可指定任意類型的變量氧枣。下面看下__block修飾OC對象。

__block id obj = [[NSObject alloc] init];

clang轉(zhuǎn)換如下:

__block結(jié)構(gòu)體
struct __Block_byref_obj_0 {
  void *__isa;
__Block_byref_obj_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 id obj;
};

//聲明部分
__attribute__((__blocks__(byref))) __Block_byref_obj_0 obj = {
    (void*)0,
    (__Block_byref_obj_0 *)&obj,
    33554432,
    sizeof(__Block_byref_obj_0),
    __Block_byref_id_object_copy_131,
    __Block_byref_id_object_dispose_131,
    [[NSObject alloc] init]
}

Block截獲對象這一小節(jié)中别垮,當(dāng)Block從棧復(fù)制到堆上時挑胸,使用copy函數(shù)持有截獲的對象,當(dāng)Block被廢棄時宰闰,使用dispose釋放截獲的對象茬贵。
在__block說明符修飾對象時,在__block變量結(jié)構(gòu)體中看到了copy和dispose函數(shù)移袍,那說明當(dāng)__block變量從棧上復(fù)制到堆上時解藻,使用copy函數(shù)持有賦值給__block變量的對象,當(dāng)堆上的__block變量被廢棄時葡盗,使用dispose函數(shù)釋放賦值給__block變量的對象螟左。

由此可知,只要堆上的__block結(jié)構(gòu)體實例變量沒有被釋放觅够,那么__block變量就不會被釋放胶背。

五、Block循環(huán)引用

原因:在Block內(nèi)部使用對象類型的變量喘先,該變量持有Block钳吟,當(dāng)Block從棧上復(fù)制到堆上時,Block同時持有了對象類型變量窘拯,那么當(dāng)對象類型釋放時红且,由于變量和Block互相引用導(dǎo)致內(nèi)存泄漏,舉個例子:

typedef void (^block)(id obj);

@property (nonatomic, copy) block blk;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.array = [NSMutableArray array];
    self.blk = ^(id obj){
        [self.array addObject:obj];
        NSLog(@"array count = %ld",[self.array count]);
    };
}

這樣寫如果這個VC被pop涤姊,那么這個VC是釋放不了的暇番,VC持有Block,Block內(nèi)部持有VC思喊。

循環(huán)引用.jpg

修改一下:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.array = [NSMutableArray array];
    ViewController * __weak temp = self;
    self.blk = ^(id obj){
        [temp.array addObject:obj];
        NSLog(@"array count = %ld",[temp.array count]);
    };
}

循環(huán)引用消失:


循環(huán)引用消失.jpg

在此根據(jù)自己的項目中使用到的Block場景壁酬,來總結(jié)下Block使用時的注意事項,說不定項目中真的有內(nèi)存泄漏呢

1恨课、UIView 的 animation動畫塊使用了Block舆乔,內(nèi)部使用self不會循環(huán)引用,為什么呢

答:UIView 動畫塊是類方法庄呈,不被self持有蜕煌,所以不會循環(huán)引用派阱。

2诬留、Monsary也使用了Block來設(shè)置控件的布局,Block內(nèi)部使用self,為什么不會循環(huán)引用呢

答:看源碼可以看出文兑,Monsary使用的Block是當(dāng)做參數(shù)傳遞的盒刚,即便block內(nèi)部持有self,設(shè)置布局的view持有block绿贞,但是block不持有view因块,當(dāng)block執(zhí)行完后就釋放了,self的引用計數(shù)-1籍铁,所以block也不會持有self涡上,所以不會導(dǎo)致循環(huán)引用。

3拒名、reactiveCocoa如果不使用@weakify @strongify吩愧,會循環(huán)引用,兩個宏就等于下邊代碼:

__weak typeof(self) weakSelf = self;
__strong typeof(weakSelf) strongSelf = weakSelf;

六增显、總結(jié)

以上幾篇文章基本就把Block(以及__block變量)的定義雁佳、語法、應(yīng)用同云、原理介紹完了糖权,主要的目的還是能更靈活的應(yīng)用于項目。

歡迎提出寶貴意見炸站,喜歡贊一下吧星澳。

圖有點low,莫見怪旱易,哈哈哈...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末募判,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子咒唆,更是在濱河造成了極大的恐慌届垫,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件全释,死亡現(xiàn)場離奇詭異装处,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)浸船,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門妄迁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來数冬,“玉大人嗓化,你說我怎么就攤上這事×饕耄” “怎么了封字?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵黔州,是天一觀的道長耍鬓。 經(jīng)常有香客問我,道長流妻,這世上最難降的妖魔是什么牲蜀? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮绅这,結(jié)果婚禮上涣达,老公的妹妹穿的比我還像新娘。我一直安慰自己证薇,他們只是感情好度苔,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浑度,像睡著了一般林螃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俺泣,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天疗认,我揣著相機(jī)與錄音,去河邊找鬼伏钠。 笑死横漏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的熟掂。 我是一名探鬼主播缎浇,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赴肚!你這毒婦竟也來了素跺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤誉券,失蹤者是張志新(化名)和其女友劉穎指厌,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踊跟,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡踩验,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了商玫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箕憾。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拳昌,靈堂內(nèi)的尸體忽然破棺而出袭异,到底是詐尸還是另有隱情,我是刑警寧澤炬藤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布御铃,位于F島的核電站碴里,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏畅买。R本人自食惡果不足惜并闲,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一细睡、第九天 我趴在偏房一處隱蔽的房頂上張望谷羞。 院中可真熱鬧,春花似錦溜徙、人聲如沸湃缎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗓违。三九已至,卻和暖如春图贸,著一層夾襖步出監(jiān)牢的瞬間蹂季,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工疏日, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留偿洁,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓沟优,卻偏偏與公主長得像涕滋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子挠阁,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

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