二十二、代理模式

1. 何為代理模式

代理模式的幾種形式:

(1)遠(yuǎn)程代理(remote proxy):為位于不同地址空間或網(wǎng)絡(luò)上的對象提供本地代表武鲁。
(2)虛擬代理(virtual proxy):根據(jù)需要常見重型對象澳叉。
(3)保護(hù)代理(protection proxy):根據(jù)各種訪問權(quán)限控制對原對象的訪問。
(4)智能引用代理(smart-reference proxy):通過對真正對象的引用進(jìn)行計(jì)數(shù)來管理內(nèi)存账千。也用于鎖定真正對象,讓其他對象不能對其進(jìn)行修改暗膜。

代理模式:為其他對象提供一種代理以控制對這個(gè)對象的訪問匀奏。

通常,代理是一種替代或者占位学搜,它控制對另一些對象的訪問娃善,而這些對象可能是遠(yuǎn)程對象,創(chuàng)建的開銷較大的對象瑞佩,或者是對安全性有要求的對象聚磺。本片博文只重點(diǎn)介紹虛擬代理
  代理模式的思想是使用一個(gè)基本上跟實(shí)體對象行為相同的代理钉凌∵肿睿客戶端可以“透明地”使用代理,不必知悉所面對的只是一個(gè)代理而不是實(shí)體對象御雕。當(dāng)客戶端請求某些創(chuàng)建開銷較大的功能時(shí),代理將把請求轉(zhuǎn)發(fā)給實(shí)體對象滥搭,準(zhǔn)備好請求的功能并返回給客戶端酸纲,客戶端不知道幕后發(fā)生了什么,代理和實(shí)體對象同樣擁有客戶端要求的行為瑟匆。圖1-1解釋了這一思想闽坡。

圖1-1 代理模式的類圖

當(dāng)客戶端向Proxy對象發(fā)送request消息時(shí),Proxy對象會把這個(gè)消息轉(zhuǎn)發(fā)給Proxy對象之中的RealSubject對象愁溜。RealSubject會實(shí)施實(shí)際的操作間接滿足客戶端的需求疾嗅。

在運(yùn)行時(shí),我們可以想象這樣一個(gè)場景:客戶端以抽象類型引用一個(gè)對象冕象,這個(gè)引用實(shí)際上是個(gè)Proxy對象代承,Proxy對象本身有一個(gè)對RealSubject實(shí)例的引用,以后如果你接到請求渐扮,此實(shí)例將執(zhí)行高強(qiáng)度的工作论悴。這個(gè)運(yùn)行時(shí)的場景如圖1-2所示:

1-2 代理模式在運(yùn)行時(shí)的一種可能的對象結(jié)構(gòu)

2. iOS中的代理模式

iOS中的代理主要由三部分組成:

  • 協(xié)議:用來指定代理雙方可以做什么掖棉,必須做什么
  • 代理:根據(jù)指定的協(xié)議,完成委托方需要實(shí)現(xiàn)的功能
  • 委托:根據(jù)指定的協(xié)議膀估,指定代理去完成什么功能

圖2-1描述了三者之間的關(guān)系:

圖2-1 協(xié)議幔亥、代理和委托三折之間的關(guān)系

從上圖中我們可以看到三方之間的關(guān)系,在實(shí)際應(yīng)用中通過協(xié)議來規(guī)定代理雙方的行為察纯,協(xié)議中的內(nèi)容一般都是方法列表帕棉,當(dāng)然也可以定義屬性。

2.1 協(xié)議(Protocol)

協(xié)議是公共的定義饼记,如果只是某個(gè)類使用笤昨,我們常做的就是寫在某個(gè)類中;如果是多個(gè)類都是用同一個(gè)協(xié)議握恳,建議創(chuàng)建一個(gè)Protocol文件瞒窒,在這個(gè)文件中定義協(xié)議。遵循的協(xié)議可以被繼承乡洼,例如我們常用的UTableView崇裁,由于繼承自UIScrollView,所以也將UIScrollViewDelegate也繼承了過來束昵,我們可以通過代理方法獲取UITableView偏移量等狀態(tài)參數(shù)拔稳。

協(xié)議只能定義公用的一套接口,類似于一個(gè)約束代理雙方的作用锹雏。但不能提供具體的實(shí)現(xiàn)方法巴比,實(shí)現(xiàn)方法需要代理對象去實(shí)現(xiàn)。協(xié)議可以繼承其他協(xié)議礁遵,并且可以繼承多個(gè)協(xié)議轻绞,在iOS中對象是不支持多繼承的,而協(xié)議可以多繼承佣耐。

@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>

協(xié)議有兩個(gè)修飾符@optional和@required政勃,創(chuàng)建一個(gè)協(xié)議如果沒有聲明,默認(rèn)是@required狀態(tài)的兼砖。這兩個(gè)修飾符只是約定代理是否強(qiáng)制需要遵守協(xié)議奸远,如果@required狀態(tài)的方法代理沒有遵守,會報(bào)一個(gè)黃色的警告讽挟,只是起一個(gè)約束的作用懒叛,沒有其他功能。

無論是@optional還是@required耽梅,在委托方調(diào)用代理方法時(shí)都需要做一個(gè)判斷薛窥,判斷代理是否實(shí)現(xiàn)當(dāng)前方法,否則會導(dǎo)致崩潰褐墅。

在iOS中一個(gè)代理可以有多個(gè)委托方拆檬,而一個(gè)委托方也可以有多個(gè)代理洪己。代理對象在很多情況下其實(shí)是可以復(fù)用的,可以創(chuàng)建多個(gè)代理對象為多個(gè)委托方服務(wù)竟贯,在下面將會通過一個(gè)小例子介紹一下控制器代理的復(fù)用答捕。

2.2 代碼實(shí)現(xiàn)

(1)首先定義一個(gè)協(xié)議類,來定義公共協(xié)議

@protocol LoginProtocol
@optional
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password;
@end

(2)定義委托類屑那,這里簡單實(shí)現(xiàn)了一個(gè)用戶登錄功能拱镐,將用戶登錄后的賬號密碼傳遞出去,有代理來處理具體登錄細(xì)節(jié)

#import #import "LoginProtocol.h"
/**
 *  當(dāng)前類是委托類持际。用戶登錄后沃琅,讓代理對象去實(shí)現(xiàn)登錄的具體細(xì)節(jié),委托類不需要知道其中實(shí)現(xiàn)的具體細(xì)節(jié)蜘欲。
 */
@interface LoginViewController : UIViewController
// 通過屬性來設(shè)置代理對象
@property (nonatomic, weak) id delegate;
@end

@implementation LoginViewController
- (void)loginButtonClick:(UIButton *)button {
  // 判斷代理對象是否實(shí)現(xiàn)這個(gè)方法益眉,沒有實(shí)現(xiàn)會導(dǎo)致崩潰
  if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) {
      // 調(diào)用代理對象的登錄方法,代理對象去實(shí)現(xiàn)登錄方法
      [self.delegate userLoginWithUsername:self.username.text password:self.password.text];
  }
}

(3)代理方姥份,實(shí)現(xiàn)具體的登錄流程郭脂,委托方不需要知道實(shí)現(xiàn)細(xì)節(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];
}
 
/**
 *  代理方實(shí)現(xiàn)具體登錄細(xì)節(jié)
 */
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password {
    NSLog(@"username : %@, password : %@", username, password);
}

2.3 代理實(shí)現(xiàn)的原理

(1)代理的實(shí)現(xiàn)流程

在iOS中代理的本質(zhì)就是代理對象內(nèi)存的傳遞和操作,我們在委托類設(shè)置代理對象之后澈歉,實(shí)際上只是用一個(gè)id類型 的指針將代理對象進(jìn)行了一個(gè)弱引用展鸡。委托方讓代理方執(zhí)行操作,實(shí)際上是在委托類中向這個(gè)id類型指針指向的對象發(fā)送消息埃难,而這個(gè)id類型指針指向的對象莹弊,就是代理對象。如圖2-2所示:

圖2-2 代理的實(shí)現(xiàn)原理

通過上面這張圖我們發(fā)現(xiàn)涡尘,其實(shí)委托方的代理屬性本質(zhì)上就是代理對象自身忍弛,設(shè)置委托代理就是代理屬性指針指向代理對象,相當(dāng)于代理對象只是在委托方中調(diào)用自己的方法悟衩,如果方法沒有實(shí)現(xiàn)就會導(dǎo)致崩潰剧罩。從崩潰的信息上來看,就可以看出來是代理方?jīng)]有實(shí)現(xiàn)協(xié)議中的方法導(dǎo)致的崩潰座泳。

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

(2)代理的內(nèi)存管理

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

我們定義的指針默認(rèn)都是__strong類型的,而屬性本質(zhì)上也是一個(gè)成員變量和set诫给、get方法構(gòu)成的香拉,strong類型的指針會造成強(qiáng)引用啦扬,必定會影響一個(gè)對象的生命周期,這也就會形成循環(huán)引用凫碌。如圖2-3所示:

圖2-3 強(qiáng)引用

上圖中扑毡,由于代理對象使用強(qiáng)引用指針,引用創(chuàng)建的委托方LoginVC對象盛险,并且成為LoginVC的代理瞄摊。這就會導(dǎo)致LoginVC的delegate屬性強(qiáng)引用代理對象,導(dǎo)致循環(huán)引用的問題苦掘,最終兩個(gè)對象都無法正常釋放换帜。

我們將LoginVC對象的delegate屬性,設(shè)置為弱引用屬性鹤啡。這樣在代理對象生命周期存在時(shí)惯驼,可以正常為我們工作,如果代理對象被釋放递瑰,委托方和代理對象都不會因?yàn)閮?nèi)存釋放導(dǎo)致的Crash祟牲。如圖2-4所示:

圖2-4 弱引用

下面兩種方式都是弱引用代理對象,但是第一種在代理對象被釋放后不會導(dǎo)致崩潰泣矛,而第二種會導(dǎo)致崩潰疲眷。

@property (nonatomic, weak) delegate;
@property (nonatomic, assign) delegate;

weak和assign是一種“非擁有關(guān)系”的指針,通過這兩種修飾符修飾的指針變量您朽,都不會改變被引用對象的引用計(jì)數(shù)狂丝。但是在一個(gè)對象被釋放后,weak會自動將指針指向nil哗总,而assign則不會几颜。在iOS中,向nil發(fā)送消息時(shí)不會導(dǎo)致崩潰的讯屈,所以assign就會導(dǎo)致野指針的錯(cuò)誤unrecognized selector sent to instance蛋哭。

3. 控制器瘦身-代理對象

在項(xiàng)目中用到比較多的控件應(yīng)該就有UITableView了,有的頁面往往UITableView的處理邏輯很多涮母,這就是導(dǎo)致控制器臃腫的一個(gè)很大的原因谆趾。對于這種問題,我們可以考慮給控制器瘦身叛本,通過代理對象的方式給控制器瘦身沪蓬。

這是平常控制器使用UITableView来候,如圖3-1所示:

圖3-1 常用寫法

這是我們優(yōu)化之后的控制器構(gòu)成跷叉,如圖3-2所示:

圖3-2 代理對象

從上面兩張圖可以看出,我們將UITableView的delegate和DataSource單獨(dú)拿出來,由一個(gè)代理對象類進(jìn)行控制云挟,只將必須控制器處理的邏輯傳遞給控制器處理梆砸。

UITableView的數(shù)據(jù)處理、展示邏輯和簡單的邏輯交互都由代理對象去處理园欣,和控制器相關(guān)的邏輯處理傳遞出來帖世,交由控制器來處理,這樣控制器的工作少了很多俊庇,而且耦合度也大大降低了狮暑。這樣一來,我們只需要將需要處理的工作交由代理對象處理辉饱,并傳入一些參數(shù)即可搬男。

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

(1)代理對象

.h文件的聲明

typedef void (^selectCell) (NSIndexPath *indexPath);
/**
 *  代理對象(UITableView的協(xié)議需要聲明在.h文件中,不然外界在使用的時(shí)候會報(bào)黃色警告彭沼,看起來不太舒服)
 */
@interface TableViewDelegateObj : NSObject <UITableViewDelegate, UITableViewDataSource>
 
/**
 *  創(chuàng)建代理對象實(shí)例缔逛,并將數(shù)據(jù)列表傳進(jìn)去
 *  代理對象將消息傳遞出去,是通過block的方式向外傳遞消息的
 *  @return 返回實(shí)例對象
 */
+ (instancetype)createTableViewDelegateWithDataList:(NSArray *)dataList
                                        selectBlock:(selectCell)selectBlock;
@end

代理對象.m文件中的實(shí)現(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];
    // 將點(diǎn)擊事件通過block的方式傳遞出去
    self.selectBlock(indexPath);
}
@end

(2)外界控制器的調(diào)用

self.tableDelegate = [TableViewDelegateObj createTableViewDelegateWithDataList:self.dataList 
                                                                   selectBlock:^(NSIndexPath *indexPath) {
    NSLog(@"點(diǎn)擊了%ld行cell", (long)indexPath.row);
}];
self.tableView.delegate = self.tableDelegate;
self.tableView.dataSource = self.tableDelegate;

在控制器中只需要?jiǎng)?chuàng)建一個(gè)代理對象類姓惑,并將UITableView的delegate和dataSource都交給代理對象去處理褐奴,讓代理對象成為UITableView的代理,解決了控制器臃腫以及和UITableView的解藕于毙。

上面的代碼只是簡單的實(shí)現(xiàn)了點(diǎn)擊cell的功能敦冬,如果有其他需求大多也都可以在代理對象中進(jìn)行處理。使用代理對象類還有一個(gè)好處唯沮,就是如果多個(gè)UITableView邏輯一樣或類似脖旱,代理對象是可以復(fù)用的。

4. 非正式協(xié)議

在iOS2.0之前還沒有引入@Protocol正式協(xié)議之前介蛉,實(shí)現(xiàn)協(xié)議的功能主要是通過給NSObject添加Category的方式萌庆。這種通過Category的方式,相對于iOS2.0之后引入的@Protocol币旧,就叫做非正式協(xié)議践险。

正如上面所說的,非正式協(xié)議一般都是以NSObject的Category的方式存在的吹菱。由于是對NSObject進(jìn)行的Category巍虫,所以所有基于NSObject的子類,都接受了所定義的非正式協(xié)議鳍刷。對于@Protocol來說編譯器會在編譯期檢查語法錯(cuò)誤垫言,而非正式協(xié)議則不會檢查是否實(shí)現(xiàn)。

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

// 由于是使用的Category前痘,所以需要用self來判斷方法是否實(shí)現(xiàn)
if ([self respondsToSelector:@selector(userLoginWithUsername:password:)]) {
    [self userLoginWithUsername:self.username.text password:self.password.text];
}
  • 非正式協(xié)議示例

在iOS早期也使用了大量非正式協(xié)議凛捏,例如CALayerDelegate就是非正式協(xié)議的一種實(shí)現(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

5. delegate和block的選擇

這兩種消息傳遞的方式坯癣,沒有哪個(gè)更好、哪個(gè)不好....我們應(yīng)該區(qū)分的是在什么情況下應(yīng)該用什么最欠,用什么更合適示罗!

  • 多個(gè)消息傳遞氮凝,應(yīng)該使用delegate呀忧。在有多個(gè)消息傳遞時(shí),用delegate實(shí)現(xiàn)更合適先誉,看起來也更清晰拌阴。block就不太好了绍绘,這個(gè)時(shí)候block反而不便于維護(hù),而且看起來非常臃腫迟赃,很別扭陪拘。例如UIKit的UITableView中有很多代理如果都換成block實(shí)現(xiàn),我們腦海里想一下這個(gè)場景纤壁,這里就不用代碼寫例子了.....那簡直看起來不能忍受左刽。

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

  • 代理更加面相過程欠痴,block則更面向結(jié)果。從設(shè)計(jì)模式的角度來說馍佑,代理更佳面向過程斋否,而block更佳面向結(jié)果。例如我們使用NSXMLParserDelegate代理進(jìn)行XML解析拭荤,NSXMLParserDelegate中有很多代理方法茵臭,NSXMLParser會不間斷調(diào)用這些方法將一些轉(zhuǎn)換的參數(shù)傳遞出來,這就是NSXMLParser解析流程舅世,這些通過代理來展現(xiàn)比較合適旦委。而例如一個(gè)網(wǎng)絡(luò)請求回來,就通過success雏亚、failure代碼塊來展示就比較好缨硝。

  • 從性能上來說,block的性能消耗要略大于delegate罢低,因?yàn)閎lock會涉及到棧區(qū)向堆區(qū)拷貝等操作查辩,時(shí)間和空間上的消耗都大于代理胖笛。而代理只是定義了一個(gè)方法列表,在遵守協(xié)議對象的objc_protocol_list中添加一個(gè)節(jié)點(diǎn)宜岛,在運(yùn)行時(shí)向遵守協(xié)議的對象發(fā)送消息即可长踊。

代理

上面圖中代理1可以被設(shè)置,代理2和代理3設(shè)置的時(shí)候被劃了叉萍倡,是因?yàn)檫@個(gè)步驟是錯(cuò)誤的操作身弊。我們上面說過,delegate只是一個(gè)保存某個(gè)代理對象的地址列敲,如果設(shè)置多個(gè)代理相當(dāng)于重新賦值阱佛,只有最后一個(gè)設(shè)置的代理才會被真正賦值。

??單例對象最好不要用delegate戴而。單例對象由于始終都只是同一個(gè)對象凑术,如果使用delegate,就會造成我們上面說的delegate屬性被重新賦值的問題填硕,最終只能有一個(gè)對象可以正常響應(yīng)代理方法麦萤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扁眯,隨后出現(xiàn)的幾起案子壮莹,更是在濱河造成了極大的恐慌,老刑警劉巖姻檀,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件命满,死亡現(xiàn)場離奇詭異,居然都是意外死亡绣版,警方通過查閱死者的電腦和手機(jī)胶台,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來杂抽,“玉大人诈唬,你說我怎么就攤上這事∷豸铮” “怎么了铸磅?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長杭朱。 經(jīng)常有香客問我阅仔,道長,這世上最難降的妖魔是什么弧械? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任八酒,我火速辦了婚禮,結(jié)果婚禮上刃唐,老公的妹妹穿的比我還像新娘羞迷。我一直安慰自己界轩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布闭树。 她就那樣靜靜地躺著耸棒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪报辱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天单山,我揣著相機(jī)與錄音碍现,去河邊找鬼。 笑死米奸,一個(gè)胖子當(dāng)著我的面吹牛昼接,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悴晰,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼慢睡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铡溪?” 一聲冷哼從身側(cè)響起漂辐,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棕硫,沒想到半個(gè)月后髓涯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哈扮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年纬纪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滑肉。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡包各,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出靶庙,到底是詐尸還是另有隱情问畅,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布惶洲,位于F島的核電站按声,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏恬吕。R本人自食惡果不足惜签则,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铐料。 院中可真熱鬧渐裂,春花似錦豺旬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至膝捞,卻和暖如春坦刀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔬咬。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工鲤遥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人林艘。 一個(gè)月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓盖奈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狐援。 傳聞我的和親對象是個(gè)殘疾皇子钢坦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

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