BC架構(gòu)探索之路

BC架構(gòu)探索之路


做iOS也有些年頭了妻顶,最近把項(xiàng)目核心模塊的架構(gòu)重新設(shè)計(jì)了一番,這里做一些記錄匈子。
首先河胎,我們要對(duì)基礎(chǔ)的設(shè)計(jì)模式有一定的認(rèn)知。這些基礎(chǔ)的設(shè)計(jì)模式虎敦,便是MVC游岳、MVVM政敢、VIPER

MVC胚迫、MVVM


關(guān)于 MVC 喷户,斯坦福的 Paul 老頭有一張經(jīng)典的圖示,相信大部分iOSer都看過(guò):

mvc.png

當(dāng)有多個(gè)模塊時(shí)访锻,我們需要有多個(gè) MVC 互相配合:

MVCs working together.png

可以看到褪尝,多個(gè)模塊之間的交互都是通過(guò) Controller 層。以上就是 MVC 的概覽期犬,那么 MVVM 是什么樣的呢河哑?

MVVM 是 Model-View-ViewModel 的縮寫(xiě)。其實(shí)在 MVC 的基礎(chǔ)上再稍進(jìn)一步龟虎,把 Controller 與 View 之間的數(shù)據(jù)傳遞過(guò)程獨(dú)立出來(lái)璃谨,封裝成一個(gè)模塊,叫做 ViewModel 鲤妥,這就成了 MVVM 了佳吞。在 MVVM 的基礎(chǔ)上,通常還會(huì)使用雙向綁定技術(shù)棉安,使得 View 和 ViewModel 之間可以自動(dòng)同步底扳。

VIPER


viper.png

VIPER ,全稱 View-Interactor-Presenter-Entity-Router 垂券。這是另一種細(xì)分 MVC 而得到的架構(gòu)。從上圖可以看到羡滑, VIPER 實(shí)際上是將 MVC 中的 Controller 細(xì)化為了三個(gè)模塊菇爪,即 Presenter、Interactor柒昏、Router 凳宙。 Entity 負(fù)責(zé)數(shù)據(jù)持久化, Interactor 負(fù)責(zé)業(yè)務(wù)相關(guān)的邏輯計(jì)算等职祷, Presenter 則負(fù)責(zé)將業(yè)務(wù)數(shù)據(jù)傳遞給 View 氏涩,也負(fù)責(zé)處理 View 的事件。大部分 View 的事件是交由邏輯側(cè) interactor 處理有梆,在 interactor 處理完后會(huì)觸發(fā)必要的 UI 刷新是尖。跳轉(zhuǎn)相關(guān)的 View 事件則交由 Router 處理。

可以看到泥耀, VIPER 和 MVVM 并不矛盾饺汹,我們可以在 MVVM 的基礎(chǔ)上繼續(xù)細(xì)化得到 VIPER , ViewModel 相關(guān)的邏輯放在 Presenter 中即可痰催。

同樣兜辞,當(dāng)有多個(gè)模塊時(shí)迎瞧,我們需要有多個(gè) VIPER 互相配合。

縱覽


可以看到傳統(tǒng)架構(gòu)的進(jìn)化過(guò)程: MVC -> MVVM -> VIPER 逸吵。這是一個(gè)對(duì)架構(gòu)不斷細(xì)化的過(guò)程凶硅。在工程實(shí)踐中,我們的業(yè)務(wù)采用什么架構(gòu)扫皱,需要根據(jù)業(yè)務(wù)的形態(tài)和頻繁變動(dòng)的模塊而定足绅。

不知大家有沒(méi)有發(fā)現(xiàn),以上所述的架構(gòu)解決的是單個(gè)業(yè)務(wù)模塊內(nèi)的職責(zé)劃分問(wèn)題啸罢,并沒(méi)有解決如何將多個(gè)業(yè)務(wù)模塊組合在一起的問(wèn)題编检。即多個(gè) MVC 或者 多個(gè) VIPER 之間如何配合?實(shí)踐中我們發(fā)現(xiàn):

  • 通過(guò)對(duì) MVC 的進(jìn)一步細(xì)分扰才,可以從單個(gè)業(yè)務(wù)模塊的角度上緩解 MVC 中 Controller 中心化所導(dǎo)致的 massive view controller 的問(wèn)題允懂,但對(duì)于有眾多業(yè)務(wù)模塊的 Controller 來(lái)說(shuō), massive view controller 依然得不到解決衩匣,即中心化的 Controller 需要做大量膠水層的工作蕾总,管理各個(gè)子 Controller 。
  • 用好傳統(tǒng)架構(gòu)琅捏,可以保證單個(gè)業(yè)務(wù)模塊內(nèi)的代碼的可復(fù)用性生百,但并不能避免業(yè)務(wù)之間的互相影響。簡(jiǎn)單說(shuō)柄延,就是修改業(yè)務(wù) A 的 bug 時(shí)蚀浆,可能會(huì)給業(yè)務(wù) B 引入 bug 。
  • ...

歸根結(jié)底搜吧,就是因?yàn)闆](méi)有一種更為宏觀的組合模塊的架構(gòu)體系市俊。正是為了解決如何將多個(gè)業(yè)務(wù)模塊組合在一起的問(wèn)題,我設(shè)計(jì)了一套 BC 的架構(gòu)體系滤奈。

BC


BC 摆昧,全稱 BusinessController ,是一種為解決業(yè)務(wù)模塊耦合和管理問(wèn)題而生的架構(gòu)體系蜒程。

為了表明 BC 的思想和實(shí)踐效果绅你,這里我以 UIViewController 的瘦身為例進(jìn)行闡述。眾所周知昭躺, iOS 開(kāi)發(fā)最讓人頭痛的問(wèn)題之一就是 UIViewController 的代碼過(guò)于龐大忌锯,難以維護(hù)。更有網(wǎng)友戲謔稱 MVC 為 massive view controller 领炫。

Massive View Controller

iOS 系統(tǒng)默認(rèn)以 UIViewController 扮演 Controller 的角色汉规,推出一個(gè)界面就是 push 一個(gè) UIViewController 。因此作為一個(gè)界面的總管, UIViewController 管理著各個(gè)子模塊针史,也包攬了眾多的邊界模糊的工作晶伦。每當(dāng)我們需要新增一個(gè)業(yè)務(wù)功能,首先就要找到對(duì)應(yīng)的 UIViewController 啄枕,再在其中進(jìn)行編碼婚陪,如下述代碼所示:

@interface ViewController ()

@property (nonatomic, assign) BOOL A_LogicFlag;
@property (nonatomic, assign) BOOL B_LogicFlag;
... (keep adding flags)

@property (nonatomic, strong) A_ControllerClass *A_Controller;
@property (nonatomic, strong) B_ControllerClass *B_Controller;
... (keep adding modules)

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.A_Controller = [A_ControllerClass new];
    [self.view addSubview:self.A_Controller.view];
    __weak typeof(self) weakSelf = self;
    [self.A_Controller sendRequestOnCompletion:^(BOOL success){
        weakSelf.A_LogicFlag = YES;
    }];
    
    self.B_Controller = [B_ControllerClass new];
    self.B_Controller.delegate = self.A_Controller;
    
    ... (keep adding code)
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    __weak typeof(self) weakSelf = self;
    [self.B_Controller sendRequestOnCompletion:^(BOOL success){
        weakSelf.B_LogicFlag = YES;
    }];
    
    ... (keep adding code)
}

@end

以上代碼已經(jīng)把每一個(gè)業(yè)務(wù)邏輯封裝為一個(gè)個(gè)模塊,然后在 UIViewController 中管理和維系各個(gè)業(yè)務(wù)模塊間的關(guān)系频祝,這是我們?nèi)粘9ぷ髦凶畛R?jiàn)的代碼泌参。很明顯,隨著業(yè)務(wù)模塊的不斷增加常空,整個(gè) UIViewController 的代碼量將會(huì)無(wú)上限的增加沽一。并且各個(gè)業(yè)務(wù)都在這個(gè) UIViewController 中修改代碼,很容易互相引入bug漓糙,產(chǎn)生耦合铣缠。

如果有細(xì)心的讀者,會(huì)發(fā)現(xiàn)這其中還有時(shí)序問(wèn)題昆禽。怎么講蝗蛙?假設(shè)現(xiàn)在我們有一個(gè)模塊 C ,我們想要做一個(gè)小改動(dòng):將 A 模塊的初始化時(shí)機(jī)放在 C 模塊的數(shù)據(jù)請(qǐng)求返回成功后醉鳖。這是個(gè)很簡(jiǎn)單的改動(dòng)捡硅,只需將 A 模塊的初始化工作放入 C 模塊的數(shù)據(jù)請(qǐng)求返回的 completion block 里:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.C_Controller = [C_ControllerClass new];
    __weak typeof(self) weakSelf = self;
    [self.C_Controller sendRequestOnCompletion:^(BOOL success){
        weakSelf.A_Controller = [A_ControllerClass new];
        [weakSelf.view addSubview:weakSelf.A_Controller.view];
        [weakSelf.A_Controller sendRequestOnCompletion:^(BOOL success){
            weakSelf.A_LogicFlag = YES;
        }];
    }];
    
    self.B_Controller = [B_ControllerClass new];
    self.B_Controller.delegate = self.A_Controller;
    
    ... (keep adding code)
}

若不仔細(xì)看看,難以發(fā)現(xiàn)以上代碼已經(jīng)有了 bug 盗棵。因?yàn)槲覀冄舆t了 A_Controller 的初始化壮韭,所以在 B_Controller 設(shè)置 delegate 時(shí),寫(xiě)入的 A_Controller 是 nil 纹因。這就是時(shí)序依賴喷屋, B_Controller 在設(shè)置 delegate 時(shí),要求 A_Controller 已經(jīng)完成了初始化辐怕”泼桑看似這種時(shí)序問(wèn)題在所難免从绘,其實(shí)不然寄疏。在 BC 架構(gòu)中,我將描述一種解決該時(shí)序問(wèn)題的方案僵井。

另外陕截,由于 coder 在 VC 中有著極高的自由度,所以當(dāng) coder 在做一些小特性時(shí)批什,會(huì)直接把代碼寫(xiě)在 VC 中农曲。大家為省事不再去為小功能獨(dú)立創(chuàng)建模塊,這樣 VC 中的代碼會(huì)更加混亂不堪。

  • 無(wú)限增長(zhǎng)的代碼量
  • 魚(yú)龍混雜的耦合關(guān)系
  • 復(fù)雜的時(shí)序問(wèn)題
  • 過(guò)度自由引入的混亂
  • ...

讓我們來(lái)看看 BC 的架構(gòu)體系如何來(lái)解決這些問(wèn)題乳规。

BC 實(shí)現(xiàn)

我們讓 UIViewController 只負(fù)責(zé)持有和維護(hù)一個(gè)業(yè)務(wù)模塊( businessController )的數(shù)組形葬,其并不關(guān)心數(shù)組中每個(gè)業(yè)務(wù)模塊的具體實(shí)現(xiàn)。我們定義一個(gè) businessController 的基類暮的,或者協(xié)議笙以。這里我們以協(xié)議為例,定義協(xié)議 BusinessController 冻辩。

// Define.h
@protocol BusinessController <NSObject>
@end

// ViewController.h
@interface ViewController : UIViewController
@property (nonatomic, strong) NSMutableArray<id<BusinessController>> *businessControllers;
@end

首先猖腕,我們希望能夠?qū)?View Controller 的狀態(tài)事件通知給 Business Controller ,而 Business Controller 可以選擇性的實(shí)現(xiàn)這些事件恨闪。所以我們先定義一個(gè)協(xié)議 ViewControllerEvents 倘感。因?yàn)槭强蛇x擇性實(shí)現(xiàn),所以為 optional 咙咽。

// Define.h
@protocol ViewControllerEvents <NSObject>
@optional
- (void)jx_viewDidLoad;
- (void)jx_viewWillAppear;
- (void)jx_viewDidAppear;
- (void)jx_viewWillDisappear;
- (void)jx_viewDidDisappear;
// ... 其它主框架的事件也可放在這里
@end

然后使 BusinessController 遵循 ViewControllerEvents 協(xié)議老玛,這樣在 BusinessController 就有了監(jiān)聽(tīng) VC 事件的能力,并且可以自動(dòng)補(bǔ)全這些方法名犁珠。

// Define.h
@protocol BusinessController <ViewControllerEvents>
@required
// 建立一個(gè)vc的弱引用逻炊,用于訪問(wèn)vc
@property (nonatomic, weak) ViewController *viewController;
@end

接著, VC 需要向業(yè)務(wù)模塊發(fā)送這些狀態(tài)事件犁享。以 viewWillAppear 為例余素,

// ViewController.m
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [self.businessControllers enumerateObjectsUsingBlock:^(id<BusinessController>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:@selector(jx_viewWillAppear)]) {
            [obj jx_viewWillAppear];
        }
    }];
}

現(xiàn)在,當(dāng)我們需要新增一個(gè)模塊 A 時(shí)炊昆,只需使其遵循 BusinessController 協(xié)議桨吊,一切就像在一個(gè)全新的 VC 中編碼一樣,十分清爽凤巨。

// A_ControllerClass.m
- (void)jx_viewWillAppear {
    // do some logic request or other business logics ...
}

最后视乐,我們只需在 VC 中添加各個(gè)業(yè)務(wù)模塊,讓整個(gè)流程跑通:

// ViewController.m
- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self addBusinessControllers:@[[A_ControllerClass new],
                                   [B_ControllerClass new],
                                   [C_ControllerClass new],
                                   ...]];
}

至此敢茁, VC 中的代碼就被我們劃分為了許許多多的模塊佑淀。可是彰檬,業(yè)務(wù)模塊之間伸刃,是需要通信的,那我們又如何解決這個(gè)通信問(wèn)題呢逢倍?我們最容易想到的是兩種常規(guī)的通信方式—— NSNotification 和 delegate 捧颅。

首先, NSNotification 是不合適的较雕。這是一種全局通知碉哑,整個(gè) APP 都會(huì)收到。我們希望的結(jié)果是, ViewController 實(shí)例一中的模塊 A 給模塊 B 發(fā)消息時(shí)扣典,不會(huì)發(fā)送到 ViewController 實(shí)例二中的模塊 B 去妆毕。

那我們就用 delegate 吧?—— NO贮尖! 第一设塔,使用 delegate 我們需要不斷的去維護(hù)那些對(duì)象之間的 delegate 關(guān)系(即在 VC 中編寫(xiě) delegate 的依賴關(guān)系,A.delegate = B)远舅,這也會(huì)引入 Massive View Controller 中提到的時(shí)序問(wèn)題闰蛔。第二,若是模塊 A 的代理事件模塊 B 和模塊 C 都需要監(jiān)聽(tīng)图柏,我們還需要將 delegate 做成數(shù)組序六。咦,真夠惡心蚤吹。

所以例诀,我們能否找到一種更好的方式來(lái)解決通信問(wèn)題呢?

這里我提供的解決方案是使用 OC 的消息轉(zhuǎn)發(fā)特性(對(duì)消息轉(zhuǎn)發(fā)不太了解的同學(xué)裁着,可以學(xué)習(xí)一下《Effective Objective-C 2.0》中消息轉(zhuǎn)發(fā)的章節(jié))繁涂。首先我們創(chuàng)建一個(gè)消息中心 CommunicationCenter ,一個(gè)消息協(xié)議 BusinessControllerConversation 二驰。讓消息中心遵循消息協(xié)議扔罪,但其內(nèi)部不實(shí)現(xiàn)任何方法,其只做轉(zhuǎn)發(fā)桶雀,將消息轉(zhuǎn)發(fā)給每一個(gè)實(shí)現(xiàn)了該消息的業(yè)務(wù)模塊( BC )矿酵。接收消息的 BC 也遵循 BusinessControllerConversation 協(xié)議。

// Define.h
@protocol BusinessControllerConversation <NSObject>
@end

// Define.h
@protocol BusinessController <ViewControllerEvents, BusinessControllerConversation>
@required
// 建立一個(gè)vc的弱引用矗积,用于訪問(wèn)vc
@property (nonatomic, weak) ViewController *viewController;
@end

// CommunicationCenter.m
@interface CommunicationCenter : NSObject <BusinessControllerConversation>
// 建立一個(gè)vc的弱引用全肮,用于訪問(wèn)vc
@property (nonatomic, weak) ViewController *viewController;
@end

// CommunicationCenter.m
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL selector = anInvocation.selector;
    [self.viewController.businessControllers enumerateObjectsUsingBlock:^(id<BusinessController> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj respondsToSelector:selector]) {
            [anInvocation invokeWithTarget:obj];
        }
    }];
}

接著,我們?cè)?VC 中創(chuàng)建并持有一個(gè)消息中心棘捣。

// ViewController.h
@property (nonatomic, strong) CommunicationCenter *communicationCenter;

// ViewController.m
_communicationCenter = [CommunicationCenter new];

這樣辜腺,當(dāng)我們的業(yè)務(wù)模塊之間需要通信時(shí),將消息定義在 BusinessControllerConversation 中乍恐,然后直接向消息中心發(fā)送消息即可评疗。例如當(dāng)前頁(yè)面的刷新按鈕被點(diǎn)擊了,但管理刷新按鈕的模塊并不管當(dāng)前頁(yè)面有哪些模塊需要刷新禁熏,它只管將該消息拋到消息中心壤巷。而需要刷新的業(yè)務(wù)模塊邑彪,則實(shí)現(xiàn)該消息即可瞧毙。

// Define.h
@protocol BusinessControllerConversation <NSObject>
@optional
- (void)msg_refreshButtonClicked;
@end

// B_ControllerClass.m
- (void)refreshBtnClicked {
    [self.viewController.communicationCenter msg_refreshBtnClicked];
}

// A_ControllerClass.m
- (void)msg_refreshBtnClicked {
    // do some business logic ...
}

由此,我們實(shí)現(xiàn)了單個(gè)VC中,模塊之間一對(duì)多的互相通信宙彪。這里值得注意的是矩动,模塊 A 和模塊 B 的耦合度幾乎降至最低。因?yàn)?A 和 B 之間互相都不知道對(duì)方释漆,不需要設(shè)置對(duì)方為 delegate 悲没,也不會(huì)有建立依賴的時(shí)序問(wèn)題。 BC 都全部面向消息編程男图,即面向協(xié)議編程示姿。

這就是使用 CommunicationCenter 進(jìn)行統(tǒng)一轉(zhuǎn)發(fā)的通信方式所帶來(lái)的極大好處:消息發(fā)送方不需要關(guān)心誰(shuí)接收消息,其只管通知一下某事件發(fā)生了逊笆。消息接收方也不需要關(guān)心誰(shuí)發(fā)送的消息栈戳,其只管接收消息做出反應(yīng)。這樣使業(yè)務(wù)模塊間的耦合性降至最低难裆。

不難發(fā)現(xiàn)子檀,只要是業(yè)務(wù)模塊 BC 所需要的事件,我們都可以通過(guò) CommunicationCenter 進(jìn)行轉(zhuǎn)發(fā)乃戈。所以我們讓 CommunicationCenterBusinessController 遵循 ViewControllerEvents 協(xié)議褂痰,這樣 ViewController 中的狀態(tài)事件,我們直接拋給 CommunicationCenter 即可症虑。狀態(tài)事件會(huì)經(jīng)過(guò) CommunicationCenter 路由至業(yè)務(wù) BC 缩歪。

// ViewController.m
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [self.communicationCenter jx_viewWillAppear];
}

在采用 BC 的架構(gòu)之后,所有的模塊都需要?jiǎng)?chuàng)建 BC 谍憔,再也沒(méi)有隨意散落在 VC 中的代碼驶冒。

至此,我們實(shí)現(xiàn)了將 VC 中的業(yè)務(wù)模塊逐一打散韵卤,各自為營(yíng)骗污,也支持業(yè)務(wù)模塊之間的靈活通信。其代碼量無(wú)限增長(zhǎng)的問(wèn)題沈条、代碼糅雜在一起魚(yú)龍混雜的問(wèn)題等需忿,都得到了解決。

BC 與傳統(tǒng)架構(gòu)


BC_Overview.png

BC 設(shè)計(jì)模式的通信結(jié)構(gòu)如上圖所示( Owner 即文中的 ViewController )蜡歹。 Owner 將主流程事件發(fā)至消息中心屋厘,由消息中心路由至各個(gè) Module 。而各個(gè) Module 之間也通過(guò)消息中心轉(zhuǎn)發(fā)至其他 Module 月而。

可以看到 BC 和傳統(tǒng)的 MVC 汗洒, MVVM , VIPER 的關(guān)系不是互斥的,是并存的父款。從 MVC 到 MVVM 到 VIPER 是對(duì)架構(gòu)的不斷細(xì)化溢谤。而 BC 則是提供了一種劃分模塊的機(jī)制瞻凤。即一個(gè) Module 可以是 Model ,可以是 View 世杀,也可以是包含了 MVC 的一個(gè)完整的模塊阀参。在使用 MVC , MVVM 瞻坝, VIPER 等設(shè)計(jì)模式時(shí)蛛壳,我們可以同時(shí)使用 BC 來(lái)幫助我們組織各個(gè)模塊。通過(guò) BC 所刀,我們將根據(jù)不同架構(gòu)設(shè)計(jì)的不同模塊有機(jī)的結(jié)合了起來(lái)衙荐。

Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市浮创,隨后出現(xiàn)的幾起案子赫模,更是在濱河造成了極大的恐慌,老刑警劉巖蒸矛,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瀑罗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雏掠,警方通過(guò)查閱死者的電腦和手機(jī)斩祭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乡话,“玉大人摧玫,你說(shuō)我怎么就攤上這事“笄啵” “怎么了诬像?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)闸婴。 經(jīng)常有香客問(wèn)我坏挠,道長(zhǎng),這世上最難降的妖魔是什么邪乍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任降狠,我火速辦了婚禮,結(jié)果婚禮上庇楞,老公的妹妹穿的比我還像新娘榜配。我一直安慰自己,他們只是感情好吕晌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蛋褥。 她就那樣靜靜地躺著,像睡著了一般睛驳。 火紅的嫁衣襯著肌膚如雪烙心。 梳的紋絲不亂的頭發(fā)上膜廊,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音弃理,去河邊找鬼。 笑死屎蜓,一個(gè)胖子當(dāng)著我的面吹牛痘昌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播炬转,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辆苔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了扼劈?” 一聲冷哼從身側(cè)響起驻啤,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荐吵,沒(méi)想到半個(gè)月后骑冗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡先煎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年贼涩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薯蝎。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遥倦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出占锯,到底是詐尸還是另有隱情袒哥,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布消略,位于F島的核電站堡称,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏艺演。R本人自食惡果不足惜粮呢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钞艇。 院中可真熱鬧啄寡,春花似錦、人聲如沸哩照。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)飘弧。三九已至识藤,卻和暖如春砚著,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痴昧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工稽穆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赶撰。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓舌镶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親豪娜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子餐胀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355