你真的了解iOS代理設(shè)計模式嗎醉拓?

轉(zhuǎn)載H售滤!

http://www.cocoachina.com/ios/20160317/15696.html


本文是投稿文章罚拟,作者:劉小壯

項目中我們經(jīng)常會用到代理的設(shè)計模式,這是iOS中一種消息傳遞的方式完箩,也可以通過這種方式來傳遞一些參數(shù)赐俗。這篇文章會涵蓋代理的使用技巧和原理,以及代

理的內(nèi)存管理等方面的知識弊知。我會通過這些方面的知識阻逮,帶大家真正領(lǐng)略代理的奧妙。寫的有點多秩彤,但都是干貨叔扼,我能寫下去,不知道你有沒有耐心看下去漫雷。本人能

力有限瓜富,如果文章中有什么問題或沒有講到的點,請幫忙指出降盹,十分感謝与柑!

iOS中消息傳遞方式

在iOS中有很多種消息傳遞方式,這里先簡單介紹一下各種消息傳遞方式蓄坏。

通知:在iOS中由通知中心進行消息接收和消息廣播价捧,是一種一對多的消息傳遞方式。

代理:是一種通用的設(shè)計模式涡戳,iOS中對代理支持的很好结蟋,由代理對象、委托者渔彰、協(xié)議三部分組成嵌屎。

block:iOS4.0中引入的一種回調(diào)方法,可以將回調(diào)處理代碼直接寫在block代碼塊中胳岂,看起來邏輯清晰代碼整齊编整。

target action:通過將對象傳遞到另一個類中,在另一個類中將該對象當做target的方式乳丰,來調(diào)用該對象方法,從內(nèi)存角度來說和代理類似内贮。

KVO:NSObject的Category-NSKeyValueObserving产园,通過屬性監(jiān)聽的方式來監(jiān)測某個值的變化汞斧,當值發(fā)生變化時調(diào)用KVO的回調(diào)方法。

.....當然還有其他回調(diào)方式什燕,這里只是簡單的列舉粘勒。

代理的基本使用

代理是一種通用的設(shè)計模式,在iOS中對代理設(shè)計模式支持的很好屎即,有特定的語法來實現(xiàn)代理模式庙睡,OC語言可以通過@Protocol實現(xiàn)協(xié)議。

代理主要由三部分組成:

協(xié)議:用來指定代理雙方可以做什么技俐,必須做什么乘陪。

代理:根據(jù)指定的協(xié)議,完成委托方需要實現(xiàn)的功能雕擂。

委托:根據(jù)指定的協(xié)議啡邑,指定代理去完成什么功能。

這里用一張圖來闡述一下三方之間的關(guān)系:

圖例

Protocol-協(xié)議的概念

從上圖中我們可以看到三方之間的關(guān)系井赌,在實際應(yīng)用中通過協(xié)議來規(guī)定代理雙方的行為谤逼,協(xié)議中的內(nèi)容一般都是方法列表,當然也可以定義屬性仇穗,我會在后續(xù)文章中順帶講一下協(xié)議中定義屬性流部。

協(xié)

議是公共的定義,如果只是某個類使用纹坐,我們常做的就是寫在某個類中枝冀。如果是多個類都是用同一個協(xié)議,建議創(chuàng)建一個Protocol文件恰画,在這個文件中定義

協(xié)議宾茂。遵循的協(xié)議可以被繼承,例如我們常用的UITableView拴还,由于繼承自UIScrollView的緣故跨晴,所以也將

UIScrollViewDelegate繼承了過來,我們可以通過代理方法獲取UITableView偏移量等狀態(tài)參數(shù)片林。

協(xié)議只能定義公用的一套接口端盆,類似于一個約束代理雙方的作用。但不能提供具體的實現(xiàn)方法费封,實現(xiàn)方法需要代理對象去實現(xiàn)焕妙。協(xié)議可以繼承其他協(xié)議,并且可以繼承多個協(xié)議弓摘,在iOS中對象是不支持多繼承的焚鹊,而協(xié)議可以多繼承。

//?當前協(xié)議繼承了三個協(xié)議韧献,這樣其他三個協(xié)議中的方法列表都會被繼承過來

@protocol?LoginProtocol

-?(void)userLoginWithUsername:(NSString?*)username?password:(NSString?*)password;

@end

協(xié)議有兩個修飾符@optional和@required末患,創(chuàng)建一個協(xié)議如果沒有聲明研叫,默認是@required狀態(tài)的。這兩

個修飾符只是約定代理是否強制需要遵守協(xié)議璧针,如果@required狀態(tài)的方法代理沒有遵守嚷炉,會報一個黃色的警告,只是起一個約束的作用探橱,沒有其他功能申屹。

無論是@optional還是@required,在委托方調(diào)用代理方法時都需要做一個判斷隧膏,判斷代理是否實現(xiàn)當前方法哗讥,否則會導致崩潰。

示例:

//?判斷代理對象是否實現(xiàn)這個方法私植,沒有實現(xiàn)會導致崩潰

if?([self.delegate?respondsToSelector:@selector(userLoginWithUsername:password:)])?{

[self.delegate?userLoginWithUsername:self.username.text?password:self.password.text];

}

下面我們將用一個小例子來講解一下這個問題:

示例:假設(shè)我在公司正在敲代碼忌栅,敲的正開心呢,突然口渴了曲稼,想喝一瓶紅茶索绪。這時我就可以拿起手機去外賣app上定一個紅茶,然后外賣app就會下單給店鋪并讓店鋪給我送過來贫悄。

這個過程中瑞驱,外賣app就是我的代理,我就是委托方窄坦,我買了一瓶紅茶并付給外賣app錢唤反,這就是購買協(xié)議。我只需要從外賣app上購買就可以鸭津,具體的操作都由外賣app去處理彤侍,我只需要最后接收這瓶紅茶就可以。我付的錢就是參數(shù)逆趋,最后送過來的紅茶就是處理結(jié)果盏阶。

但是我買紅茶的同時,我還想吃一份必勝客披薩闻书,我需要另外向必勝客app去訂餐名斟,上面的外賣app并沒有這個功能。我又向必勝客購買了一份披薩魄眉,必勝客當做我的代理去為我做這份披薩砰盐,并最后送到我手里。這就是多個代理對象坑律,我就是委托方岩梳。

代理

在iOS中一個代理可以有多個委托方,而一個委托方也可以有多個代理。我指定了外賣app和必勝客兩個代理蒋腮,也可以再指定麥當勞等多個代理淘捡,委托方也可以為多個代理服務(wù)藕各。

代理對象在很多情況下其實是可以復用的池摧,可以創(chuàng)建多個代理對象為多個委托方服務(wù),在下面將會通過一個小例子介紹一下控制器代理的復用激况。

下面是一個簡單的代理:

首先定義一個協(xié)議類作彤,來定義公共協(xié)議

#import

@protocol?LoginProtocol

@optional

-?(void)userLoginWithUsername:(NSString?*)username?password:(NSString?*)password;

@end

定義委托類,這里簡單實現(xiàn)了一個用戶登錄功能乌逐,將用戶登錄后的賬號密碼傳遞出去竭讳,有代理來處理具體登錄細節(jié)。

#import?#import?"LoginProtocol.h"

/**

*??當前類是委托類浙踢。用戶登錄后绢慢,讓代理對象去實現(xiàn)登錄的具體細節(jié),委托類不需要知道其中實現(xiàn)的具體細節(jié)洛波。

*/

@interface?LoginViewController?:?UIViewController

//?通過屬性來設(shè)置代理對象

@property?(nonatomic,?weak)?id?delegate;

@end

實現(xiàn)部分:

@implementation?LoginViewController

-?(void)loginButtonClick:(UIButton?*)button?{

//?判斷代理對象是否實現(xiàn)這個方法胰舆,沒有實現(xiàn)會導致崩潰

if?([self.delegate?respondsToSelector:@selector(userLoginWithUsername:password:)])?{

//?調(diào)用代理對象的登錄方法,代理對象去實現(xiàn)登錄方法

[self.delegate?userLoginWithUsername:self.username.text?password:self.password.text];

}

}

代理方蹬挤,實現(xiàn)具體的登錄流程缚窿,委托方不需要知道實現(xiàn)細節(jié)。

//?遵守登錄協(xié)議

@interface?ViewController?()

@end

@implementation?ViewController

-?(void)viewDidLoad?{

[super?viewDidLoad];

LoginViewController?*loginVC?=?[[LoginViewController?alloc]?init];

loginVC.delegate?=?self;

[self.navigationController?pushViewController:loginVC?animated:YES];

}

/**

*??代理方實現(xiàn)具體登錄細節(jié)

*/

-?(void)userLoginWithUsername:(NSString?*)username?password:(NSString?*)password?{

NSLog(@"username?:?%@,?password?:?%@",?username,?password);

}

代理使用原理

代理實現(xiàn)流程

iOS中代理的本質(zhì)就是代理對象內(nèi)存的傳遞和操作焰扳,我們在委托類設(shè)置代理對象后倦零,實際上只是用一個id類型的指針將代理對象進行了一個弱引用。委托方讓代

理方執(zhí)行操作吨悍,實際上是在委托類中向這個id類型指針指向的對象發(fā)送消息扫茅,而這個id類型指針指向的對象,就是代理對象育瓜。

代理原理

通過上面這張圖我們發(fā)現(xiàn)葫隙,其實委托方的代理屬性本質(zhì)上就是代理對象自身,設(shè)置委托代理就是代理屬性指針指向代理對象爆雹,相當于代理對象只是在委托方中調(diào)用自己的方法停蕉,如果方法沒有實現(xiàn)就會導致崩潰。從崩潰的信息上來看钙态,就可以看出來是代理方?jīng)]有實現(xiàn)協(xié)議中的方法導致的崩潰慧起。

而協(xié)議只是一種語法,是聲明委托方中的代理屬性可以調(diào)用協(xié)議中聲明的方法册倒,而協(xié)議中方法的實現(xiàn)還是有代理方完成蚓挤,而協(xié)議方和委托方都不知道代理方有沒有完成,也不需要知道怎么完成。

代理內(nèi)存管理

為什么我們設(shè)置代理屬性都使用weak呢灿意?

我們定義的指針默認都是__strong類型的估灿,而屬性本質(zhì)上也是一個成員變量和set、get方法構(gòu)成的缤剧,strong類型的指針會造成強引用馅袁,必定會影響一個對象的生命周期,這也就會形成循環(huán)引用荒辕。

強引用

上圖中汗销,由于代理對象使用強引用指針,引用創(chuàng)建的委托方LoginVC對象抵窒,并且成為LoginVC的代理弛针。這就會導致LoginVC的delegate屬性強引用代理對象,導致循環(huán)引用的問題李皇,最終兩個對象都無法正常釋放削茁。

弱引用

我們將LoginVC對象的delegate屬性,設(shè)置為弱引用屬性掉房。這樣在代理對象生命周期存在時茧跋,可以正常為我們工作,如果代理對象被釋放圃阳,委托方和代理對象都不會因為內(nèi)存釋放導致的Crash厌衔。

但是,這樣還有點問題捍岳,真的不會崩潰嗎富寿?

下面兩種方式都是弱引用代理對象,但是第一種在代理對象被釋放后不會導致崩潰锣夹,而第二種會導致崩潰页徐。

@property?(nonatomic,?weak)?iddelegate;

@property?(nonatomic,?assign)?iddelegate;

weak

和assign是一種“非擁有關(guān)系”的指針,通過這兩種修飾符修飾的指針變量银萍,都不會改變被引用對象的引用計數(shù)变勇。但是在一個對象被釋放后,weak會自動

將指針指向nil贴唇,而assign則不會搀绣。在iOS中,向nil發(fā)送消息時不會導致崩潰的戳气,所以assign就會導致野指針的錯誤

unrecognized selector sent to instance链患。

所以我們?nèi)绻揎棿韺傩裕€是用weak修飾吧瓶您,比較安全麻捻。

控制器瘦身-代理對象

為什么要使用代理對象纲仍?

隨著項目越來越復雜,控制器也隨著業(yè)務(wù)的增加而變得越來越臃腫贸毕。對于這種情況郑叠,很多人都想到了最近比較火的MVVM設(shè)計模式。但是這種模式學習曲線很大不好掌握明棍,對于新項目來說可以使用乡革,對于一個已經(jīng)很復雜的大中型項目,就不太好動框架這層的東西了击蹲。

在項目中用到比較多的控件應(yīng)該就有UITableView了署拟,有的頁面往往UITableView的處理邏輯很多,這就是導致控制器臃腫的一個很大的原因歌豺。對于這種問題,我們可以考慮給控制器瘦身心包,通過代理對象的方式給控制器瘦身类咧。

什么是代理對象

這是平常控制器使用UITableView(圖畫的難看蟹腾,主要是意思理解就行)

常用寫法

這是我們優(yōu)化之后的控制器構(gòu)成

代理對象

從上面兩張圖可以看出痕惋,我們將UITableView的delegate和DataSource單獨拿出來,由一個代理對象類進行控制娃殖,只將必須控制器處理的邏輯傳遞給控制器處理值戳。

UITableView的數(shù)據(jù)處理、展示邏輯和簡單的邏輯交互都由代理對象去處理炉爆,和控制器相關(guān)的邏輯處理傳遞出來堕虹,交由控制器來處理,這樣控制器的工作少了很多芬首,而且耦合度也大大降低了赴捞。這樣一來,我們只需要將需要處理的工作交由代理對象處理郁稍,并傳入一些參數(shù)即可赦政。

下面我們用一段代碼來實現(xiàn)一個簡單的代理對象

代理對象.h文件的聲明

typedef?void?(^selectCell)?(NSIndexPath?*indexPath);

/**

*??代理對象(UITableView的協(xié)議需要聲明在.h文件中,不然外界在使用的時候會報黃色警告耀怜,看起來不太舒服)

*/

@interface?TableViewDelegateObj?:?NSObject?[UITableViewDelegate,?UITableViewDataSource](因識別問題恢着,這里將尖括號改為方括號)

/**

*??創(chuàng)建代理對象實例,并將數(shù)據(jù)列表傳進去

*??代理對象將消息傳遞出去财破,是通過block的方式向外傳遞消息的

*??@return?返回實例對象

*/

+?(instancetype)createTableViewDelegateWithDataList:(NSArray?*)dataList

selectBlock:(selectCell)selectBlock;

@end

代理對象.m文件中的實現(xiàn)

#import?"TableViewDelegateObj.h"

@interface?TableViewDelegateObj?()

@property?(nonatomic,?strong)?NSArray???*dataList;

@property?(nonatomic,?copy)???selectCell?selectBlock;

@end

@implementation?TableViewDelegateObj

+?(instancetype)createTableViewDelegateWithDataList:(NSArray?*)dataList

selectBlock:(selectCell)selectBlock?{

return?[[[self?class]?alloc]?initTableViewDelegateWithDataList:dataList

selectBlock:selectBlock];

}

-?(instancetype)initTableViewDelegateWithDataList:(NSArray?*)dataList?selectBlock:(selectCell)selectBlock?{

self?=?[super?init];

if?(self)?{

self.dataList?=?dataList;

self.selectBlock?=?selectBlock;

}

return?self;

}

-?(UITableViewCell?*)tableView:(UITableView?*)tableView?cellForRowAtIndexPath:(NSIndexPath?*)indexPath?{

static?NSString?*identifier?=?@"cell";

UITableViewCell?*cell?=?[tableView?dequeueReusableCellWithIdentifier:identifier];

if?(!cell)?{

cell?=?[[UITableViewCell?alloc]?initWithStyle:UITableViewCellStyleDefault?reuseIdentifier:identifier];

}

cell.textLabel.text?=?self.dataList[indexPath.row];

return?cell;

}

-?(NSInteger)tableView:(UITableView?*)tableView?numberOfRowsInSection:(NSInteger)section?{

return?self.dataList.count;

}

-?(void)tableView:(UITableView?*)tableView?didSelectRowAtIndexPath:(NSIndexPath?*)indexPath?{

[tableView?deselectRowAtIndexPath:indexPath?animated:NO];

//?將點擊事件通過block的方式傳遞出去

self.selectBlock(indexPath);

}

@end

外界控制器的調(diào)用非常簡單掰派,幾行代碼就搞定了。

self.tableDelegate?=?[TableViewDelegateObj?createTableViewDelegateWithDataList:self.dataList

selectBlock:^(NSIndexPath?*indexPath)?{

NSLog(@"點擊了%ld行cell",?(long)indexPath.row);

}];

self.tableView.delegate?=?self.tableDelegate;

self.tableView.dataSource?=?self.tableDelegate;

在控制器中只需要創(chuàng)建一個代理對象類狈究,并將UITableView的delegate和dataSource都交給代理對象去處理碗淌,讓代理對象成為UITableView的代理盏求,解決了控制器臃腫以及和UITableView的解藕。

上面的代碼只是簡單的實現(xiàn)了點擊cell的功能亿眠,如果有其他需求大多也都可以在代理對象中進行處理碎罚。使用代理對象類還有一個好處,就是如果多個UITableView邏輯一樣或類似纳像,代理對象是可以復用的荆烈。

非正式協(xié)議

簡介

在iOS2.0之前還沒有引入@Protocol正式協(xié)議之前,實現(xiàn)協(xié)議的功能主要是通過給NSObject添加Category的方式竟趾。這種通過Category的方式憔购,相對于iOS2.0之后引入的@Protocol,就叫做非正式協(xié)議岔帽。

如上面所說的玫鸟,非正式協(xié)議一般都是以NSObject的Category的方式存在的。由于是對NSObject進行的Category犀勒,所以所有基于

NSObject的子類屎飘,都接受了所定義的非正式協(xié)議。對于@Protocol來說編譯器會在編譯期檢查語法錯誤贾费,而非正式協(xié)議則不會檢查是否實現(xiàn)钦购。

非正式協(xié)議中沒有@Protocol的@optional和@required之分,和@Protocol一樣在調(diào)用的時候褂萧,需要進行判斷方法是否實現(xiàn)押桃。

//?由于是使用的Category,所以需要用self來判斷方法是否實現(xiàn)

if?([self?respondsToSelector:@selector(userLoginWithUsername:password:)])?{

[self?userLoginWithUsername:self.username.text?password:self.password.text];

}

非正式協(xié)議示例

在iOS早期也使用了大量非正式協(xié)議导犹,例如CALayerDelegate就是非正式協(xié)議的一種實現(xiàn)唱凯,非正式協(xié)議本質(zhì)上就是Category。

@interface?NSObject?(CALayerDelegate)

-?(void)displayLayer:(CALayer?*)layer;

-?(void)drawLayer:(CALayer?*)layer?inContext:(CGContextRef)ctx;

-?(void)layoutSublayersOfLayer:(CALayer?*)layer;

-?(nullable?id)actionForLayer:(CALayer?*)layer?forKey:(NSString?*)event;

@end

代理和block的選擇

在iOS中的回調(diào)方法有很多锡足,而代理和block功能更加相似波丰,都是直接進行回調(diào),那我們應(yīng)該用哪個呢舶得,或者說哪個更好呢掰烟?

其實這兩種消息傳遞的方式,沒有哪個更好沐批、哪個不好直說....我們應(yīng)該區(qū)分的是在什么情況下應(yīng)該用什么纫骑,用什么更合適!下面我將會簡單的介紹一下在不同情況下代理和block的選擇:

個消息傳遞九孩,應(yīng)該使用delegate先馆。在有多個消息傳遞時,用delegate實現(xiàn)更合適躺彬,看起來也更清晰煤墙。block就不太好了梅惯,這個時候block

反而不便于維護,而且看起來非常臃腫仿野,很別扭铣减。例如UIKit的UITableView中有很多代理如果都換成block實現(xiàn),我們腦海里想一下這個場

景脚作,這里就不用代碼寫例子了.....那簡直看起來不能忍受葫哗。

一個委托對象的代理屬性只能有一個代理對象,如果想要委托對象調(diào)用多個代理對象的回調(diào)應(yīng)該用block球涛。

代理

上面圖中代理1可以被設(shè)置劣针,代理2和代理3設(shè)置的時候被劃了叉,是因為這個步驟是錯誤的操作亿扁。我們上面說過捺典,delegate只是一個保存某個代理對象的地址,如果設(shè)置多個代理相當于重新賦值魏烫,只有最后一個設(shè)置的代理才會被真正賦值辣苏。

單例對象最好不要用delegate。單例對象由于始終都只是同一個對象哄褒,如果使用delegate,就會造成我們上面說的delegate屬性被重新賦值的問題煌张,最終只能有一個對象可以正常響應(yīng)代理方法呐赡。

這種情況我們可以使用block的方式,在主線程的多個對象中使用block都是沒問題的骏融,下面我們將用一個循環(huán)暴力測試一下block到底有沒有問題链嘀。

NSOperationQueue?*queue?=?[[NSOperationQueue?alloc]?init];

queue.maxConcurrentOperationCount?=?10;

for?(int?i?=?0;?i?<?100;?i++)?{

[queue?addOperationWithBlock:^{

[[LoginViewController?shareInstance]?userLoginWithSuccess:^(NSString?*username)?{

NSLog(@"TestTableViewController?:?%d",?i);

}];

}];

}

上面用NSOperationQueue創(chuàng)建了一個新的隊列,并且將最大并發(fā)數(shù)設(shè)置為10档玻,然后創(chuàng)建一個100次的循環(huán)怀泊。我們在多線

程情況下測試單例在block的情況下能否正常使用,答案是可以的误趴。但是我們還是需要注意一點霹琼,在多線程情況下因為是單例對象,我們對block中必要的

地方加鎖凉当,防止資源搶奪的問題發(fā)生枣申。

代理是可選的,而block在方法調(diào)用的時候只能通過將某個參數(shù)傳遞一個nil進去看杭,只不過這并不是什么大問題忠藤,沒有代碼潔癖的可以忽略。

[self?downloadTaskWithResumeData:resumeData

sessionManager:manager

savePath:savePath

progressBlock:nil

successBlock:successBlock

failureBlock:failureBlock];

理更加面相過程楼雹,block則更面向結(jié)果模孩。從設(shè)計模式的角度來說尖阔,代理更佳面向過程,而block更佳面向結(jié)果榨咐。例如我們使用

NSXMLParserDelegate代理進行XML解析介却,NSXMLParserDelegate中有很多代理方法,NSXMLParser會不間斷

調(diào)用這些方法將一些轉(zhuǎn)換的參數(shù)傳遞出來祭芦,這就是NSXMLParser解析流程筷笨,這些通過代理來展現(xiàn)比較合適。而例如一個網(wǎng)絡(luò)請求回來龟劲,就通過

success胃夏、failure代碼塊來展示就比較好。

從性能上來說昌跌,block的性能消耗要略大于delegate仰禀,因為block會涉及到棧區(qū)向堆區(qū)拷貝等操作,時間和空間上的消耗都大于代理蚕愤。而代理只是定義了一個方法列表答恶,在遵守協(xié)議對象的objc_protocol_list中添加一個節(jié)點,在運行時向遵守協(xié)議的對象發(fā)送消息即可萍诱。這篇文章并不是講block的悬嗓,所以不對此做過多敘述。唐巧有一篇文章介紹過block裕坊,非常推薦這篇文章去深入學習block包竹。文章地址?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市籍凝,隨后出現(xiàn)的幾起案子周瞎,更是在濱河造成了極大的恐慌,老刑警劉巖饵蒂,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件声诸,死亡現(xiàn)場離奇詭異,居然都是意外死亡退盯,警方通過查閱死者的電腦和手機彼乌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來得问,“玉大人囤攀,你說我怎么就攤上這事」常” “怎么了焚挠?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漓骚。 經(jīng)常有香客問我蝌衔,道長榛泛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任噩斟,我火速辦了婚禮曹锨,結(jié)果婚禮上喷众,老公的妹妹穿的比我還像新娘窃祝。我一直安慰自己,他們只是感情好贪壳,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布斥废。 她就那樣靜靜地躺著椒楣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪牡肉。 梳的紋絲不亂的頭發(fā)上捧灰,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音统锤,去河邊找鬼毛俏。 笑死,一個胖子當著我的面吹牛饲窿,可吹牛的內(nèi)容都是我干的煌寇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼逾雄,長吁一口氣:“原來是場噩夢啊……” “哼唧席!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嘲驾,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎迹卢,沒想到半個月后辽故,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡腐碱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年誊垢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片症见。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡喂走,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谋作,到底是詐尸還是另有隱情芋肠,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布遵蚜,位于F島的核電站帖池,受9級特大地震影響奈惑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜睡汹,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一肴甸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囚巴,春花似錦原在、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至姆坚,卻和暖如春澳泵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背兼呵。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工兔辅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人击喂。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓维苔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親懂昂。 傳聞我的和親對象是個殘疾皇子介时,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

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