RAC簡單介紹

RAC在iOS的實際開發中確實是一件有力的武器,此文將從以下幾方面講解

RACSignal

RACSubject

RACSequence

RACMulticastConnection

RACCommand

RAC常用宏

RAC-bind

RAC-過濾

RAC-映射

RAC-組合

RAC+MVVM-網絡請求

RACSignal

// 1.創建信號RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {// 3.發送信號[subscriber sendNext:@"ws"];// 4.取消信號,如果信號想要被取消,就必須返回一個RACDisposable// 信號什么時候被取消:1.自動取消,當一個信號的訂閱者被銷毀的時候機會自動取消訂閱,2.手動取消,//block什么時候調用:一旦一個信號被取消訂閱就會調用//block作用:當信號被取消時用于清空一些資源return[RACDisposable disposableWithBlock:^{NSLog(@"取消訂閱");? ? ? ? }];? ? }];// 2. 訂閱信號//subscribeNext// 把nextBlock保存到訂閱者里面// 只要訂閱信號就會返回一個取消訂閱信號的類RACDisposable *disposable = [signal subscribeNext:^(idx) {// block的調用時刻:只要信號內部發出數據就會調用這個blockNSLog(@"======%@", x);? ? }];// 取消訂閱[disposable dispose];

總結

.核心:

.核心:信號類

.信號類的作用:只要有數據改變就會把數據包裝成信號傳遞出去

.只要有數據改變就會有信號發出

.數據發出,并不是信號類發出,信號類不能發送數據

.使用方法:

.創建信號

.訂閱信號

.實現思路:

.當一個信號被訂閱,創建訂閱者,并把nextBlock保存到訂閱者里面。

.創建的時候會返回 [RACDynamicSignal createSignal:didSubscribe];

.調用RACDynamicSignal的didSubscribe

.發送信號[subscriber sendNext:value];

.拿到訂閱者的nextBlock調用

RACSubject

RACSubject 在使用中我們可以完全代替代理,代碼簡介方法。具體代碼請看demo中的RACSubject。

總結

我們完全可以用RACSubject代替代理/通知,確實方便許多

這里我們點擊TwoViewController的pop的時候 將字符串"ws"傳給了ViewController的button的title。

步驟:

1.創建信號

RACSubject *subject = [RACSubject subject];

2.訂閱信號

[subject subscribeNext:^(idx) {// block:當有數據發出的時候就會調用// block:處理數據NSLog(@"%@",x);}];

3.發送信號

[subject sendNext:value];

注意

RACSubject和RACReplaySubject的區別

RACSubject必須要先訂閱信號之后才能發送信號, 而RACReplaySubject可以先發送信號后訂閱.

RACSubject 代碼中體現為:先走TwoViewController的sendNext,后走ViewController的subscribeNext訂閱

RACReplaySubject 代碼中體現為:先走ViewController的subscribeNext訂閱,后走TwoViewController的sendNext

可按實際情況各取所需。

RACSequence

使用場景---: 可以快速高效的遍歷數組和字典。

NSString*path = [[NSBundlemainBundle] pathForResource:@"flags.plist"ofType:nil];NSArray*dictArr = [NSArrayarrayWithContentsOfFile:path];? ? [dictArr.rac_sequence.signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? } error:^(NSError*error) {NSLog(@"===error===");? ? } completed:^{NSLog(@"ok---完畢");? ? }];也可以使用宏NSDictionary*dict = @{@"key":@1,@"key2":@2};? ? [dict.rac_sequence.signal subscribeNext:^(idx) {NSLog(@"%@", x);NSString*key = x[0];NSString*value = x[1];// RACTupleUnpack宏:專門用來解析元組// RACTupleUnpack 等會右邊:需要解析的元組 宏的參數,填解析的什么樣數據// 元組里面有幾個值,宏的參數就必須填幾個RACTupleUnpack(NSString*key,NSString*value) = x;NSLog(@"%@ %@", key, value);? ? } error:^(NSError*error) {NSLog(@"===error");? ? } completed:^{NSLog(@"-----ok---完畢");? ? }];

RACMulticastConnection

當有多個訂閱者,但是我們只想發送一個信號的時候怎么辦?這時我們就可以用RACMulticastConnection,來實現。代碼示例如下

// 普通寫法, 這樣的缺點是:沒訂閱一次信號就得重新創建并發送請求,這樣很不友好RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {// didSubscribeblock中的代碼都統稱為副作用。// 發送請求---比如afnNSLog(@"發送請求啦");// 發送信號[subscriber sendNext:@"ws"];returnnil;? ? }];? ? [signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];? ? [signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];? ? [signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];

// 比較好的做法。 使用RACMulticastConnection,無論有多少個訂閱者,無論訂閱多少次,我只發送一個。// 1.發送請求,用一個信號內包裝,不管有多少個訂閱者,只想發一次請求RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {// 發送請求NSLog(@"發送請求啦");// 發送信號[subscriber sendNext:@"ws"];returnnil;? ? }];//2. 創建連接類RACMulticastConnection *connection = [signal publish];? ? [connection.signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];? ? [connection.signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];? ? [connection.signal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];//3. 連接。只有連接了才會把信號源變為熱信號[connection connect];

RACCommand

RACCommand:RAC中用于處理事件的類,可以把事件如何處理,事件中的數據如何傳遞,包裝到這個類中,他可以很方便的監控事件的執行過程,比如看事件有沒有執行完畢

使用場景:監聽按鈕點擊,網絡請求

// 普通做法// RACCommand: 處理事件// 不能返回空的信號// 1.創建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(idinput) {//block調用,執行命令的時候就會調用NSLog(@"%@",input);// input 為執行命令傳進來的參數// 這里的返回值不允許為nilreturn[RACSignal createSignal:^RACDisposable *(id subscriber) {? ? ? ? ? ? [subscriber sendNext:@"執行命令產生的數據"];returnnil;? ? ? ? }];? ? }];// 如何拿到執行命令中產生的數據呢?// 訂閱命令內部的信號// ** 方式一:直接訂閱執行命令返回的信號// 2.執行命令RACSignal *signal =[command execute:@2];// 這里其實用到的是replaySubject 可以先發送命令再訂閱// 在這里就可以訂閱信號了[signal subscribeNext:^(idx) {NSLog(@"%@",x);? ? }];

// 一般做法// 1.創建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(idinput) {//block調用,執行命令的時候就會調用NSLog(@"%@",input);// input 為執行命令傳進來的參數// 這里的返回值不允許為nilreturn[RACSignal createSignal:^RACDisposable *(id subscriber) {? ? ? ? ? ? [subscriber sendNext:@"執行命令產生的數據"];returnnil;? ? ? ? }];? ? }];// 方式二:// 訂閱信號// 注意:這里必須是先訂閱才能發送命令// executionSignals:信號源,信號中信號,signalofsignals:信號,發送數據就是信號[command.executionSignals subscribeNext:^(RACSignal *x) {? ? ? ? [x subscribeNext:^(idx) {NSLog(@"%@", x);? ? ? ? }];//? ? ? ? NSLog(@"%@", x);}];// 2.執行命令[command execute:@2];

// 高級做法// 1.創建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(idinput) {// block調用:執行命令的時候就會調用NSLog(@"%@", input);// 這里的返回值不允許為nilreturn[RACSignal createSignal:^RACDisposable *(id subscriber) {? ? ? ? ? ? [subscriber sendNext:@"發送信號"];returnnil;? ? ? ? }];? ? }];// 方式三// switchToLatest獲取最新發送的信號,只能用于信號中信號。[command.executionSignals.switchToLatest subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 2.執行命令[command execute:@3];

// switchToLatest--用于信號中信號// 創建信號中信號RACSubject *signalofsignals = [RACSubject subject];? ? RACSubject *signalA = [RACSubject subject];// 訂閱信號//? ? [signalofsignals subscribeNext:^(RACSignal *x) {//? ? ? ? [x subscribeNext:^(id x) {//? ? ? ? ? ? NSLog(@"%@", x);//? ? ? ? }];//? ? }];// switchToLatest: 獲取信號中信號發送的最新信號[signalofsignals.switchToLatest subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[signalofsignals sendNext:signalA];? ? [signalA sendNext:@4];

// 監聽事件有沒有完成//注意:當前命令內部發送數據完成,一定要主動發送完成// 1.創建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(idinput) {// block調用:執行命令的時候就會調用NSLog(@"%@", input);// 這里的返回值不允許為nilreturn[RACSignal createSignal:^RACDisposable *(id subscriber) {// 發送數據[subscriber sendNext:@"執行命令產生的數據"];// *** 發送完成 **[subscriber sendCompleted];returnnil;? ? ? ? }];? ? }];// 監聽事件有沒有完成[command.executing subscribeNext:^(idx) {if([x boolValue] ==YES) {// 正在執行NSLog(@"當前正在執行%@", x);? ? ? ? }else{// 執行完成/沒有執行NSLog(@"執行完成/沒有執行");? ? ? ? }? ? }];// 2.執行命令[command execute:@1];

RAC常用宏

RAC有許多強大而方便的宏。如下

// RAC:把一個對象的某個屬性綁定一個信號,只要發出信號,就會把信號的內容給對象的屬性賦值// 給label的text屬性綁定了文本框改變的信號RAC(self.label, text) =self.textField.rac_textSignal;//? ? [self.textField.rac_textSignal subscribeNext:^(id x) {//? ? ? ? self.label.text = x;//? ? }];

/**

*? KVO

*? RACObserveL:快速的監聽某個對象的某個屬性改變

*? 返回的是一個信號,對象的某個屬性改變的信號

*/[RACObserve(self.view, center) subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];

//例 textField輸入的值賦值給label,監聽label文字改變,RAC(self.label, text) =self.textField.rac_textSignal;? ? [RACObserve(self.label, text) subscribeNext:^(idx) {NSLog(@"====label的文字變了");? ? }];

/**

*? 循環引用問題

*/@weakify(self)? ? RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {? ? ? ? @strongify(self)NSLog(@"%@",self.view);returnnil;? ? }];? ? _signal = signal;使用 @weakify(self)和@strongify(self)來避免循環引用

/**

* 元祖

* 快速包裝一個元組

* 把包裝的類型放在宏的參數里面,就會自動包裝

*/RACTuple *tuple = RACTuplePack(@1,@2,@4);// 宏的參數類型要和元祖中元素類型一致, 右邊為要解析的元祖。RACTupleUnpack_(NSNumber*num1,NSNumber*num2,NSNumber* num3) = tuple;// 4.元祖// 快速包裝一個元組// 把包裝的類型放在宏的參數里面,就會自動包裝NSLog(@"%@ %@ %@", num1, num2, num3);

RAC-bind

// 1.創建信號RACSubject *subject = [RACSubject subject];// 2.綁定信號RACSignal *bindSignal = [subject bind:^RACStreamBindBlock{// block調用時刻:只要綁定信號訂閱就會調用。不做什么事情,return^RACSignal *(idvalue,BOOL*stop){// 一般在這個block中做事 ,發數據的時候會來到這個block。// 只要源信號(subject)發送數據,就會調用block// block作用:處理源信號內容// value:源信號發送的內容,value = @3;// 如果在這里把value的值改了,那么訂閱綁定信號的值即44行的x就變了NSLog(@"接受到源信號的內容:%@", value);//返回信號,不能為nil,如果非要返回空---則empty或 alloc init。return[RACReturnSignalreturn:value];// 把返回的值包裝成信號};? ? }];// 3.訂閱綁定信號[bindSignal subscribeNext:^(idx) {NSLog(@"接收到綁定信號處理完的信號:%@", x);? ? }];// 4.發送信號[subject sendNext:@"123"];

總結

bind(綁定)的使用思想和Hook的一樣---> 都是攔截API從而可以對數據進行操作,,而影響返回數據。

發送信號的時候會來到30行的block。在這個block里我們可以對數據進行一些操作,那么35行打印的value和訂閱綁定信號后的value就會變了。變成什么樣隨你喜歡嘍。

RAC-過濾

有時候我們想要過濾一些信號,這時候我們便可以用RAC的過濾方法。過濾方法有好多種,如下代碼,從不同情況下進行了分析。

// 跳躍 : 如下,skip傳入2 跳過前面兩個值// 實際用處: 在實際開發中比如 后臺返回的數據前面幾個沒用,我們想跳躍過去,便可以用skipRACSubject *subject = [RACSubject subject];? ? [[subject skip:2] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];? ? [subject sendNext:@1];? ? [subject sendNext:@2];? ? [subject sendNext:@3];

//distinctUntilChanged:-- 如果當前的值跟上一次的值一樣,就不會被訂閱到RACSubject *subject = [RACSubject subject];? ? [[subject distinctUntilChanged] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[subject sendNext:@1];? ? [subject sendNext:@2];? ? [subject sendNext:@2];// 不會被訂閱

// take:可以屏蔽一些值,去掉前面幾個值---這里take為2 則只拿到前兩個值RACSubject *subject = [RACSubject subject];? ? [[subject take:2] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[subject sendNext:@1];? ? [subject sendNext:@2];? ? [subject sendNext:@3];

//takeLast:和take的用法一樣,不過他取的是最后的幾個值,如下,則取的是最后兩個值//注意點:takeLast 一定要調用sendCompleted,告訴他發送完成了,這樣才能取到最后的幾個值RACSubject *subject = [RACSubject subject];? ? [[subject takeLast:2] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[subject sendNext:@1];? ? [subject sendNext:@2];? ? [subject sendNext:@3];? ? [subject sendCompleted];

// takeUntil:---給takeUntil傳的是哪個信號,那么當這個信號發送信號或sendCompleted,就不能再接受源信號的內容了。RACSubject *subject = [RACSubject subject];? ? RACSubject *subject2 = [RACSubject subject];? ? [[subject takeUntil:subject2] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[subject sendNext:@1];? ? [subject sendNext:@2];? ? [subject2 sendNext:@3];// 1//? ? [subject2 sendCompleted]; // 或2[subject sendNext:@4];

// ignore: 忽略掉一些值//ignore:忽略一些值//ignoreValues:表示忽略所有的值// 1.創建信號RACSubject *subject = [RACSubject subject];// 2.忽略一些值RACSignal *ignoreSignal = [subject ignore:@2];// ignoreValues:表示忽略所有的值// 3.訂閱信號[ignoreSignal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 4.發送數據[subject sendNext:@2];

// 一般和文本框一起用,添加過濾條件// 只有當文本框的內容長度大于5,才獲取文本框里的內容[[self.textField.rac_textSignal filter:^BOOL(idvalue) {// value 源信號的內容return[value length] >5;// 返回值 就是過濾條件。只有滿足這個條件才能獲取到內容}] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];

RAC-映射

RAC的映射在實際開發中有什么用呢?比如我們想要攔截服務器返回的數據,給數據拼接特定的東西或想對數據進行操作從而更改返回值,類似于這樣的情況下,我們便可以考慮用RAC的映射,實例代碼如下

- (void)map {// 創建信號RACSubject *subject = [RACSubject subject];// 綁定信號RACSignal *bindSignal = [subject map:^id(idvalue) {// 返回的類型就是你需要映射的值return[NSStringstringWithFormat:@"ws:%@", value];//這里將源信號發送的“123” 前面拼接了ws:}];// 訂閱綁定信號[bindSignal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[subject sendNext:@"123"];

- (void)flatMap {// 創建信號RACSubject *subject = [RACSubject subject];// 綁定信號RACSignal *bindSignal = [subject flattenMap:^RACStream *(idvalue) {// block:只要源信號發送內容就會調用// value: 就是源信號發送的內容// 返回信號用來包裝成修改內容的值return[RACReturnSignalreturn:value];? ? ? ? ? ? }];// flattenMap中返回的是什么信號,訂閱的就是什么信號(那么,x的值等于value的值,如果我們操縱value的值那么x也會隨之而變)// 訂閱信號[bindSignal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送數據[subject sendNext:@"123"];? ? }

- (void)flattenMap2 {// flattenMap 主要用于信號中的信號// 創建信號RACSubject *signalofSignals = [RACSubject subject];? ? RACSubject *signal = [RACSubject subject];// 訂閱信號//方式1//? ? [signalofSignals subscribeNext:^(id x) {////? ? ? ? [x subscribeNext:^(id x) {//? ? ? ? ? ? NSLog(@"%@", x);//? ? ? ? }];//? ? }];// 方式2//? ? [signalofSignals.switchToLatest? ];// 方式3//? RACSignal *bignSignal = [signalofSignals flattenMap:^RACStream *(id value) {////? ? ? ? //value:就是源信號發送內容//? ? ? ? return value;//? ? }];//? ? [bignSignal subscribeNext:^(id x) {//? ? ? ? NSLog(@"%@", x);//? ? }];// 方式4--------也是開發中常用的[[signalofSignals flattenMap:^RACStream *(idvalue) {returnvalue;? ? }] subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號[signalofSignals sendNext:signal];? ? [signal sendNext:@"123"];}

RAC-組合

把多個信號聚合成你想要的信號,使用場景----:比如-當多個輸入框都有值的時候按鈕才可點擊。

// 思路--- 就是把輸入框輸入值的信號都聚合成按鈕是否能點擊的信號。- (void)combineLatest {? ? ? ? RACSignal *combinSignal = [RACSignal combineLatest:@[self.accountField.rac_textSignal,self.pwdField.rac_textSignal] reduce:^id(NSString*account,NSString*pwd){//reduce里的參數一定要和combineLatest數組里的一一對應。// block: 只要源信號發送內容,就會調用,組合成一個新值。NSLog(@"%@ %@", account, pwd);return@(account.length && pwd.length);? ? }];//? ? // 訂閱信號//? ? [combinSignal subscribeNext:^(id x) {//? ? ? ? self.loginBtn.enabled = [x boolValue];//? ? }];? ? // ----這樣寫有些麻煩,可以直接用RAC宏RAC(self.loginBtn, enabled) = combinSignal;}

- (void)zipWith {//zipWith:把兩個信號壓縮成一個信號,只有當兩個信號同時發出信號內容時,并且把兩個信號的內容合并成一個元祖,才會觸發壓縮流的next事件。// 創建信號ARACSubject *signalA = [RACSubject subject];// 創建信號BRACSubject *signalB = [RACSubject subject];// 壓縮成一個信號// **-zipWith-**: 當一個界面多個請求的時候,要等所有請求完成才更新UI// 等所有信號都發送內容的時候才會調用RACSignal *zipSignal = [signalA zipWith:signalB];? ? [zipSignal subscribeNext:^(idx) {NSLog(@"%@", x);//所有的值都被包裝成了元組}];// 發送信號 交互順序,元組內元素的順序不會變,跟發送的順序無關,而是跟壓縮的順序有關[signalA zipWith:signalB]---先是A后是B[signalA sendNext:@1];? ? [signalB sendNext:@2];}

// 任何一個信號請求完成都會被訂閱到// merge:多個信號合并成一個信號,任何一個信號有新值就會調用- (void)merge {// 創建信號ARACSubject *signalA = [RACSubject subject];// 創建信號BRACSubject *signalB = [RACSubject subject];//組合信號RACSignal *mergeSignal = [signalA merge:signalB];// 訂閱信號[mergeSignal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];// 發送信號---交換位置則數據結果順序也會交換[signalB sendNext:@"下部分"];? ? [signalA sendNext:@"上部分"];}

// then --- 使用需求:有兩部分數據:想讓上部分先進行網絡請求但是過濾掉數據,然后進行下部分的,拿到下部分數據- (void)then {// 創建信號ARACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {// 發送請求NSLog(@"----發送上部分請求---afn");? ? ? ? ? ? ? ? [subscriber sendNext:@"上部分數據"];? ? ? ? [subscriber sendCompleted];// 必須要調用sendCompleted方法!returnnil;? ? }];// 創建信號B,RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id subscriber) {// 發送請求NSLog(@"--發送下部分請求--afn");? ? ? ? [subscriber sendNext:@"下部分數據"];returnnil;? ? }];// 創建組合信號// then;忽略掉第一個信號的所有值RACSignal *thenSignal = [signalA then:^RACSignal *{// 返回的信號就是要組合的信號returnsignalsB;? ? }];// 訂閱信號[thenSignal subscribeNext:^(idx) {NSLog(@"%@", x);? ? }];}

// concat----- 使用需求:有兩部分數據:想讓上部分先執行,完了之后再讓下部分執行(都可獲取值)- (void)concat {// 組合// 創建信號ARACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id subscriber) {// 發送請求//? ? ? ? NSLog(@"----發送上部分請求---afn");[subscriber sendNext:@"上部分數據"];? ? ? ? [subscriber sendCompleted];// 必須要調用sendCompleted方法!returnnil;? ? }];// 創建信號B,RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id subscriber) {// 發送請求//? ? ? ? NSLog(@"--發送下部分請求--afn");[subscriber sendNext:@"下部分數據"];returnnil;? ? }];// concat:按順序去鏈接//**-注意-**:concat,第一個信號必須要調用sendCompleted// 創建組合信號RACSignal *concatSignal = [signalA concat:signalsB];// 訂閱組合信號[concatSignal subscribeNext:^(idx) {NSLog(@"%@",x);? ? }];}

作者:帥小王

鏈接:http://www.lxweimin.com/p/db772bbb6a2f

來源:簡書

簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容