ReactiveCocoa技術(shù)講解-第四講冷熱信號(hào)和并發(fā)編程

一竞漾、冷熱信號(hào):

美團(tuán)冷熱信號(hào)1
1眯搭、熱信號(hào)是主動(dòng)的,即使你沒有訂閱事件业岁,它仍然會(huì)時(shí)刻推送鳞仙。
而冷信號(hào)是被動(dòng)的,只有當(dāng)你訂閱的時(shí)候笔时,它才會(huì)發(fā)送消息繁扎。

2、熱信號(hào)可以有多個(gè)訂閱者糊闽,是一對(duì)多梳玫,信號(hào)可以與訂閱者共享信息。
而冷信號(hào)只能一對(duì)一右犹,當(dāng)有不同的訂閱者提澎,消息會(huì)重新完整發(fā)送。

二念链、為什么要區(qū)分冷盼忌、熱信號(hào):

美團(tuán)冷熱信號(hào)2
這里面引用的例子很說服力,足見臧老師的功底之深掂墓。我決定把例子在這里詳細(xì)的講解下:

self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]];
self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];

    @weakify(self)
    RACSignal *fetchData = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self)
        NSURLSessionDataTask *task = [self.sessionManager GET:@"fetchData" parameters:@{@"someParameter": @"someValue"} success:^(NSURLSessionDataTask *task, id responseObject) {
            [subscriber sendNext:responseObject];
            [subscriber sendCompleted];
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            if (task.state != NSURLSessionTaskStateCompleted) {
                [task cancel];
            }
        }];
    }];

    RACSignal *title = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"title"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"title"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *desc = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"desc"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"desc"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *renderedDesc = [desc flattenMap:^RACStream *(NSString *value) {
        NSError *error = nil;
        RenderManager *renderManager = [[RenderManager alloc] init];
        NSAttributedString *rendered = [renderManager renderText:value error:&error];
        if (error) {
            return [RACSignal error:error];
        } else {
            return [RACSignal return:rendered];
        }
    }];

    RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
    RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
    RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];

    [[RACSignal merge:@[title, desc, renderedDesc]] subscribeError:^(NSError *error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:error.domain delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
    }];

**我們不妨在demo中實(shí)際運(yùn)行一遍谦纱,不要只是單純的看代碼。切身體會(huì)下這段的問題所在君编。

分析前先下結(jié)論:

1跨嘉、信號(hào)只有被訂閱后才會(huì)產(chǎn)生值。
2吃嘿、任何信號(hào)變換的本質(zhì)都是依賴bind函數(shù)祠乃,而bind函數(shù)的實(shí)現(xiàn)在上一篇中我們已經(jīng)講過,所以這里直接有的概念就是:任何信號(hào)的轉(zhuǎn)換都是對(duì)原有信號(hào)進(jìn)行訂閱兑燥,從而產(chǎn)生新信號(hào)亮瓷。
3、這里一定要注意的是:我們?cè)谧钔鈱觿?chuàng)建信號(hào)后降瞳,在內(nèi)部對(duì)原始信號(hào)進(jìn)行訂閱時(shí)嘱支,用到的subscriber是組外層信號(hào)的訂閱者,也就是只有新創(chuàng)建的信號(hào)被訂閱時(shí),我們內(nèi)部才會(huì)間接地對(duì)原始信號(hào)進(jìn)行訂閱除师。

有了這些前置概念赢织,我們?cè)賮砜聪律厦娴拇a:

1、fetchData信號(hào)被flattenMap之后馍盟,會(huì)因?yàn)閠itle于置、desc被訂閱從而間接的被訂閱,desc被flattenMap后生成renderedDesc贞岭,等到renderedDesc被訂閱后八毯,fetchData會(huì)再次被間接訂閱,因此會(huì)有三次訂閱的過程瞄桨,也就是會(huì)產(chǎn)生三次網(wǎng)絡(luò)請(qǐng)求话速。
2、我們看到上述代碼還有一個(gè)merge操作芯侥,這里會(huì)將三個(gè)信號(hào)merge成為一個(gè)新信號(hào)泊交,創(chuàng)建了一個(gè)新的信號(hào),在這個(gè)信號(hào)被訂閱的時(shí)候柱查,把它包含的所有信號(hào)訂閱廓俭。所以我們又得到了額外的3次網(wǎng)絡(luò)請(qǐng)求。

總結(jié):每一次的訂閱都會(huì)導(dǎo)致信號(hào)被重新執(zhí)行唉工,從而引起6次網(wǎng)絡(luò)請(qǐng)求研乒,而造成這種現(xiàn)象的原因是:fetchData是一個(gè)冷信號(hào)。所以每次訂閱都會(huì)重新執(zhí)行一次淋硝。如果是熱信號(hào)雹熬,即使被訂閱多次,我們也不會(huì)谣膳,因?yàn)槊看斡嗛喐捅ǎ盘?hào)都會(huì)被執(zhí)行一次。

這篇博客中也提到了:FP(函數(shù)式編程)以及副作用的相關(guān)概念继谚,這里不在細(xì)說烈菌,大家可以自行閱讀。

三犬庇、如何處理冷僧界、熱信號(hào)

美團(tuán)冷熱信號(hào)3

RACSubject 和RACReplaySubject :

1侨嘀、RACSubject:
1.1臭挽、RACSubject是熱信號(hào),他的訂閱者在訂閱后咬腕,不會(huì)收到在訂閱前發(fā)送的信號(hào)值欢峰,只會(huì)收到從訂閱時(shí)間點(diǎn)開始后產(chǎn)生的信號(hào)值。
1.2、多個(gè)訂閱者可以共享信號(hào)值纽帖。
2宠漩、RACSubject訂閱處理邏輯

1.png

可以看到,訂閱前發(fā)送的信號(hào)訂閱者都不會(huì)收到懊直。

3扒吁、RACReplaySubject:是RACSubject子類,訂閱者在訂閱它之后會(huì)先將之前已經(jīng)發(fā)送的信號(hào)室囊,快速發(fā)送一遍給訂閱者雕崩。然后再回到當(dāng)前的現(xiàn)實(shí),等待下一個(gè)信號(hào)的到來融撞。
上面的博客中臧老師形象的用時(shí)空穿越的例子來描述:舉個(gè)生動(dòng)的例子盼铁,就好像科幻電影里面主人公穿越時(shí)間線后會(huì)先把所有的回憶快速閃過再來到現(xiàn)實(shí)一樣。(見《X戰(zhàn)警:逆轉(zhuǎn)未來》尝偎、《蝴蝶效應(yīng)》)所以我們也有理由認(rèn)定replaySubject天然也是熱信號(hào)饶火。這一點(diǎn)不得不佩服,能把抽象的知識(shí)講的富有畫面感致扯,不得不說是只有對(duì)該領(lǐng)域有了充分且足夠深入的理解才能達(dá)到這種境界肤寝,佩服!
4抖僵、RACReplaySubject的訂閱時(shí)處理邏輯如下

3.png

5醒陆、結(jié)論

RACSubject及其子類是熱信號(hào)。
RACSignal排除RACSubject類以外的是冷信號(hào)裆针。

四刨摩、冷信號(hào)轉(zhuǎn)熱信號(hào)

1、冷信號(hào)轉(zhuǎn)換成熱信號(hào)的本質(zhì)

冷信號(hào)轉(zhuǎn)換成熱信號(hào)的本質(zhì):就是使用一個(gè)subject訂閱原始信號(hào)世吨,讓其他訂閱者訂閱這個(gè)subject,這個(gè)subject就是熱信號(hào)澡刹。

2、代碼實(shí)現(xiàn):

- (void)coldSignalTransferHotSignal {
    //1耘婚、創(chuàng)建冷信號(hào)
    RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"=====cold signal subscribered");
        [[RACScheduler mainThreadScheduler] afterDelay:1.0 schedule:^{
            [subscriber sendNext:@"AAA"];
        }];
        
        [[RACScheduler mainThreadScheduler] afterDelay:3.0 schedule:^{
            [subscriber sendNext:@"BBB"];
        }];
        
        [[RACScheduler mainThreadScheduler] afterDelay:5.0 schedule:^{
            [subscriber sendCompleted];
        }];
        return nil;
    }];
    //2罢浇、創(chuàng)建subject,并訂閱冷信號(hào)
    RACSubject *subject = [RACSubject subject];
    NSLog(@"=======subject 被創(chuàng)建");
    [[RACScheduler mainThreadScheduler] afterDelay:2.0 schedule:^{
         [coldSignal subscribe:subject]; //放在主線程中訂閱
    }];
    //3沐祷、其他訂閱者訂閱subject
    [subject subscribeNext:^(id x) {
        NSLog(@"====第一個(gè)訂閱者嚷闭,收到信號(hào)值:%@",x);
    }];
    [[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{
        [subject subscribeNext:^(id x) {
            NSLog(@"=====第二個(gè)訂閱者,收到信號(hào)值:%@",x);
        }];
    }];
}

3赖临、RAC官方給出的信號(hào)轉(zhuǎn)換API:
當(dāng)然胞锰,使用這種RACSubject來訂閱冷信號(hào)得到熱信號(hào)的方式仍有一些小的瑕疵。例如subject的訂閱者提前終止了訂閱兢榨,而subject并不能終止對(duì)coldSignal的訂閱嗅榕。所以在RAC庫中對(duì)于冷信號(hào)轉(zhuǎn)化成熱信號(hào)有如下標(biāo)準(zhǔn)的封裝

- (RACMulticastConnection *)publish;
- (RACMulticastConnection *)multicast:(RACSubject *)subject;
- (RACSignal *)replay;
- (RACSignal *)replayLast;
- (RACSignal *)replayLazily;

這5個(gè)方法中顺饮,最為重要的就是- (RACMulticastConnection *)multicast:(RACSubject *)subject;這個(gè)方法了,其他幾個(gè)方法也是間接調(diào)用它的凌那。至于multiCast的實(shí)現(xiàn)兼雄,可參閱博客,原文講的很好帽蝶。
4赦肋、使用multicast: 來完善冷熱信號(hào)轉(zhuǎn)換的本質(zhì):

- (void)multiCast {
    //1、創(chuàng)建冷信號(hào)
    RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"=====cold signal subscribered");
        [[RACScheduler mainThreadScheduler] afterDelay:1.0 schedule:^{
            [subscriber sendNext:@"AAA"];
        }];
        
        [[RACScheduler mainThreadScheduler] afterDelay:3.0 schedule:^{
            [subscriber sendNext:@"BBB"];
        }];
        
        [[RACScheduler mainThreadScheduler] afterDelay:5.0 schedule:^{
            [subscriber sendCompleted];
        }];
        return nil;
    }];
    
    //使用multicast:將冷信號(hào)轉(zhuǎn)換成熱信號(hào)
    RACSubject *subject = [RACSubject subject];
    RACMulticastConnection *connection = [coldSignal multicast:subject];
    
    /*
    //1励稳、使用connect
    RACSignal *hotSignal = connection.signal;
    //主動(dòng)觸發(fā)connect
    [[RACScheduler mainThreadScheduler] afterDelay:2.0 schedule:^{
        [connection connect];
    }];
    */
    
    //2金砍、使用autoconnect
    RACSignal *hotSignal = connection.autoconnect;

    //訂閱熱信號(hào)
    [hotSignal subscribeNext:^(id x) {
        NSLog(@"====第一個(gè)訂閱者,收到信號(hào)值:%@",x);
    }];
    [[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{ //4s后開始訂閱
        [hotSignal subscribeNext:^(id x) {
            NSLog(@"====第二個(gè)訂閱者麦锯,收到信號(hào)值:%@",x);
        }];
    }];
}

注意:看publish的源碼會(huì)發(fā)現(xiàn)恕稠,其實(shí)publish就是做了上面的工作。

5扶欣、replay鹅巍、replayLatest、replayLazily對(duì)比

  • (RACSignal *)replay就是用RACReplaySubject來作為subject料祠,并立即執(zhí)行connect操作骆捧,返回connection.signal。其作用是上面提到的replay功能髓绽,即后來的訂閱者可以收到歷史值敛苇。
  • (RACSignal *)replayLast就是用容量為1的RACReplaySubject來替換- (RACSignal *)replay的subject。其作用是使后來訂閱者只收到:訂閱者訂閱前信號(hào)發(fā)送的最后一次歷史值顺呕。
  • (RACSignal *)replayLazily和- (RACSignal *)replay的區(qū)別就是:replayLazily只有在第一次訂閱的時(shí)候才訂閱sourceSignal枫攀。簡單講:直到訂閱的時(shí)候才真正創(chuàng)建一個(gè)信號(hào),源信號(hào)的訂閱代碼才開始執(zhí)行
    具體看例子:
- (void)comparisonSignal {
    //創(chuàng)建冷信號(hào)
    RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"222 冷信號(hào)(原始信號(hào))被訂閱");
        [[RACScheduler mainThreadScheduler] afterDelay:1.0 schedule:^{
            [subscriber sendNext:@"AAA"];
        }];
        
        [[RACScheduler mainThreadScheduler] afterDelay:3.0 schedule:^{
            [subscriber sendNext:@"BBB"];
        }];
        
        [[RACScheduler mainThreadScheduler] afterDelay:5.0 schedule:^{
            [subscriber sendCompleted];
        }];
        return nil;
    }];
    //分別使用以下兩種方式轉(zhuǎn)換成熱信號(hào)
//    RACSignal *hotSignal = [coldSignal replayLazily];
    RACSignal *hotSignal = [coldSignal replay];
     NSLog(@"111開始訂閱");
    //訂閱熱信號(hào)
    [hotSignal subscribeNext:^(id x) {
        NSLog(@"====第一個(gè)訂閱者株茶,收到信號(hào)值:%@",x);
    }];
    [[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{ //4s后開始訂閱
        [hotSignal subscribeNext:^(id x) {
            NSLog(@"====第二個(gè)訂閱者来涨,收到信號(hào)值:%@",x);
        }];
    }];
}
*********************************************************************
使用replay的輸出結(jié)果:
2017-12-19 16:22:00.338530+0800  222 冷信號(hào)(原始信號(hào))被訂閱
2017-12-19 16:22:00.338857+0800 111開始訂閱

使用replayLazily的輸出結(jié)果:
2017-12-19 16:23:23.577210+0800  111開始訂閱
2017-12-19 16:23:23.577920+0800  222 冷信號(hào)(原始信號(hào))被訂閱

我們可以看到,replayLazily 只會(huì)在訂閱時(shí)启盛,才會(huì)去創(chuàng)建信號(hào)蹦掐,源信號(hào)的訂閱代碼才會(huì)被執(zhí)行。

6僵闯、回到第二篇博客中的例子上卧抗,我們?yōu)榱吮苊饩W(wǎng)絡(luò)請(qǐng)求執(zhí)行多次,保證它只會(huì)執(zhí)行一次鳖粟,我們需要將冷信號(hào)轉(zhuǎn)換成熱信號(hào)(熱信號(hào)不會(huì)因?yàn)橛嗛喺叩挠嗛喩珩桑匦虏シ牛8膭?dòng)后的代碼如下:

self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]];

    self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
    self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];

    @weakify(self)
    RACSignal *fetchData = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self)
        NSURLSessionDataTask *task = [self.sessionManager GET:@"fetchData" parameters:@{@"someParameter": @"someValue"} success:^(NSURLSessionDataTask *task, id responseObject) {
            [subscriber sendNext:responseObject];
            [subscriber sendCompleted];
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            if (task.state != NSURLSessionTaskStateCompleted) {
                [task cancel];
            }
        }];
    }] replayLazily];  // 使用replayLazily 轉(zhuǎn)換成熱信號(hào)牺弹,而且保證網(wǎng)絡(luò)請(qǐng)求的代碼是直到訂閱才去執(zhí)行浦马。

    RACSignal *title = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"title"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"title"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *desc = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"desc"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"desc"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *renderedDesc = [desc flattenMap:^RACStream *(NSString *value) {
        NSError *error = nil;
        RenderManager *renderManager = [[RenderManager alloc] init];
        NSAttributedString *rendered = [renderManager renderText:value error:&error];
        if (error) {
            return [RACSignal error:error];
        } else {
            return [RACSignal return:rendered];
        }
    }];

    RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
    RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
    RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];

    [[RACSignal merge:@[title, desc, renderedDesc]] subscribeError:^(NSError *error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:error.domain delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
    }];

當(dāng)然臧老師還提到:

例如將fetchData轉(zhuǎn)換為title的block會(huì)執(zhí)行多次时呀,將fetchData轉(zhuǎn)換為desc的block也會(huì)執(zhí)行多次张漂。但是由于這些block都是無副作用的晶默,計(jì)算量并不大,可以忽略不計(jì)航攒。如果計(jì)算量大的磺陡,也需要對(duì)中間的信號(hào)進(jìn)行熱信號(hào)的轉(zhuǎn)換。不過請(qǐng)不要忽略冷熱信號(hào)的轉(zhuǎn)換本身也是有計(jì)算代價(jià)的漠畜。

這里我們也可以總結(jié)下:當(dāng)模塊代碼會(huì)重復(fù)執(zhí)行多次時(shí)币他,我們想要避免這種情況,可以采取轉(zhuǎn)換成熱信號(hào)的方式憔狞。但是假如該代碼重復(fù)執(zhí)行不會(huì)產(chǎn)生副作用蝴悉,那么我們則可以允許這種情況的存在。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瘾敢,一起剝皮案震驚了整個(gè)濱河市拍冠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌簇抵,老刑警劉巖庆杜,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碟摆,居然都是意外死亡晃财,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門典蜕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來断盛,“玉大人,你說我怎么就攤上這事愉舔≈A伲” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵屑宠,是天一觀的道長厢洞。 經(jīng)常有香客問我,道長典奉,這世上最難降的妖魔是什么躺翻? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮卫玖,結(jié)果婚禮上公你,老公的妹妹穿的比我還像新娘。我一直安慰自己假瞬,他們只是感情好陕靠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布迂尝。 她就那樣靜靜地躺著,像睡著了一般剪芥。 火紅的嫁衣襯著肌膚如雪垄开。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天税肪,我揣著相機(jī)與錄音溉躲,去河邊找鬼。 笑死益兄,一個(gè)胖子當(dāng)著我的面吹牛锻梳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播净捅,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼疑枯,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了蛔六?” 一聲冷哼從身側(cè)響起荆永,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎古今,沒想到半個(gè)月后屁魏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捉腥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年氓拼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抵碟。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桃漾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拟逮,到底是詐尸還是另有隱情撬统,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布敦迄,位于F島的核電站恋追,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏罚屋。R本人自食惡果不足惜苦囱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脾猛。 院中可真熱鬧撕彤,春花似錦、人聲如沸猛拴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至职员,卻和暖如春麻蹋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背廉邑。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國打工哥蔚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倒谷,地道東北人蛛蒙。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像渤愁,于是被迫代替她去往敵國和親牵祟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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