ReactiveCocoa 一 RACStream

When subclassing RACStream, only the methods in the main @interface body need to be overridden.

以上是RACStream類的簡要介紹中的一段話,大意為只有主類中聲明的方法需要在子類重寫。查看類實(shí)現(xiàn)文件發(fā)現(xiàn)主類中聲明的方法全部都很厚道的 return nil 液走,因此我們在介紹以下方法時會使用其子類RACSignal做演示精拟。


+ (instancetype)empty;

empty函數(shù)返回一個名為 +empty 的stream,這個stream會被立即結(jié)束裙戏,不做任何操作。


+ (instancetype)return:(id)value;

創(chuàng)建一個名為 +return: value 的stream,這個stream返回給定值后結(jié)束瘤旨。


//value:值  stop:如果設(shè)置為YES則終止后續(xù)值
typedef RACStream * (^RACStreamBindBlock)(id value, BOOL *stop);

- (instancetype)bind:(RACStreamBindBlock (^)(void))block;

原始 stream 每產(chǎn)生一個 value 將 value 傳入 RACStreamBindBlock 產(chǎn)生一個新的 stream 并訂閱這個 stream 。 當(dāng) stop 被設(shè)置為 YES 時終止后續(xù)值發(fā)送竖伯。一旦任意一個由 RACStreamBindBlock 產(chǎn)生的 stream sendError 則原始 stream sendError存哲,當(dāng)所有由 RACStreamBindBlock 產(chǎn)生的 stream sendComplete 則原始 stream sendComplete。

例:

創(chuàng)建一個signal對象發(fā)送十次值七婴,并且在其中隨機(jī)發(fā)送@" "祟偷。我們要做的是過濾掉@" "并且在接收到@"5"時終止后續(xù)發(fā)送返回一個新的signal并且發(fā)送@"a",@"b"打厘。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    //發(fā)送10次值
    for (int i = 0; i < 10; i ++) {
        //隨機(jī)發(fā)送 @" "
        BOOL empty = arc4random_uniform(2);
        if (!empty || i == 5) {
            [subscriber sendNext:[NSString stringWithFormat:@"%zd",i]];
        }
        else {
            [subscriber sendNext:@" "];
        }
    }
    [subscriber sendCompleted];
    return nil;
}] bind:^RACStreamBindBlock{
    return ^id (NSString * value, BOOL * stop) {
        if ([value isEqualToString:@" "]) { //過濾@" "
            return [RACSignal empty];
        }
        else if ([value isEqualToString:@"5"]){ //接收到 @"5" 終止
            * stop = YES;
            RACSignal * result = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                [subscriber sendNext:@"a"];
                [subscriber sendNext:@"b"];
                [subscriber sendCompleted];
                return nil;
            }];
            return result;
        }
        else {
            return [RACSignal return:value];
        }
        
    };
}];

[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];

[signal subscribeCompleted:^{
    NSLog(@"complete");
}];
/* 某次執(zhí)行結(jié)果
2018-03-27 15:14:02.334078+0800 ReactCocoaTest[91664:2403921] 1
2018-03-27 15:14:02.334390+0800 ReactCocoaTest[91664:2403921] 3
2018-03-27 15:14:02.334562+0800 ReactCocoaTest[91664:2403921] 4
2018-03-27 15:14:02.334836+0800 ReactCocoaTest[91664:2403921] a
2018-03-27 15:14:02.334957+0800 ReactCocoaTest[91664:2403921] b
2018-03-27 15:14:02.335673+0800 ReactCocoaTest[91664:2403921] complete
*/

- (instancetype)concat:(RACStream *)stream;

將 stream a與 stream b 聯(lián)結(jié)起來并產(chǎn)生一個新的 stream c修肠,只有當(dāng)前stream a sendComplete 之后 stream b 才能發(fā)送值,當(dāng) stream a 和 stream b 都 sendComplete 之后户盯,聯(lián)結(jié)產(chǎn)生的stream c 才會 sendComplete嵌施。
注意:如果聯(lián)結(jié)的兩個stream中某個stream sendError 則聯(lián)結(jié)產(chǎn)生的stream立即 sendError 。

例:

創(chuàng)建兩個stream先舷,并且各自延遲5秒 sendComplete

RACSignal * signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [[RACScheduler mainThreadScheduler]afterDelay:5 schedule:^{
        [subscriber sendCompleted];
    }];
    return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"2"];
    [[RACScheduler mainThreadScheduler]afterDelay:5 schedule:^{
        [subscriber sendCompleted];
    }];
    return nil;
}];
RACSignal * concat = [signal1 concat:signal2];
[concat subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
[concat subscribeCompleted:^{
    NSLog(@"complete");
}];
[concat subscribeError:^(NSError *error) {
    NSLog(@"error");
}];
/*
2018-03-27 16:37:18.546755+0800 ReactCocoaTest[94470:2467226] 1
2018-03-27 16:37:24.040041+0800 ReactCocoaTest[94470:2467226] 2
2018-03-27 16:37:29.513247+0800 ReactCocoaTest[94470:2467226] complete
*/

可以看到控制臺三次輸出間隔時間為5秒艰管,大家可以將signal1 或者signal2中任意一個 sendComplete 修改為 sendError 驗(yàn)證signal sendError的情況。


//- (instancetype)concat:(RACStream *)stream 的升級版 針對多個stream的情況
+ (instancetype)concat:(id<NSFastEnumeration>)streams;

- (instancetype)zipWith:(RACStream *)stream;

將 stream a 與 stream b 結(jié)合起來產(chǎn)生一個新的 stream c蒋川,當(dāng) stream a 和 stream b 都發(fā)送過一次值之后 stream c 才會將這兩個值通過RACTuple對象發(fā)送牲芋。
注意:
1.stream c 發(fā)送的 RACTuple 中的值為 stream a 與 stream b 同次發(fā)送的值。
2.stream a 與 stream b 中任意一個 sendComplete 則 stream c sendComplete捺球,當(dāng) stream a 與 stream b 任意一個 sendError 則 stream c sendError缸浦。

例:
RACSignal * signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"3"];
    [subscriber sendNext:@"4"];
    [subscriber sendNext:@"5"];
    [subscriber sendNext:@"6"];
    [[RACScheduler mainThreadScheduler]afterDelay:7 schedule:^{
        [subscriber sendError:nil];
    }];
    return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"a"];
    [subscriber sendNext:@"b"];
    [[RACScheduler mainThreadScheduler]afterDelay:5 schedule:^{
        [subscriber sendNext:@"d"];
        [subscriber sendCompleted];
    }];
    return nil;
}];
RACSignal * zip = [signal1 zipWith:signal2];
[zip subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
[zip subscribeCompleted:^{
    NSLog(@"complete");
}];
[zip subscribeError:^(NSError *error) {
    NSLog(@"error");
}];
/*
2018-03-27 17:20:15.922457+0800 ReactCocoaTest[96661:2499724] <RACTuple: 0x604000206030> (
    1,
    a
)
2018-03-27 17:20:15.922787+0800 ReactCocoaTest[96661:2499724] <RACTuple: 0x604000206010> (
    2,
    b
)
2018-03-27 17:20:21.414965+0800 ReactCocoaTest[96661:2499724] <RACTuple: 0x604000207110> (
    3,
    d
)
2018-03-27 17:20:21.415268+0800 ReactCocoaTest[96661:2499724] complete
*/   

//- (instancetype)zipWith:(RACStream *)stream 的升級版 針對多個stream的情況
+ (instancetype)zip:(id<NSFastEnumeration>)streams;

- (instancetype)flattenMap:(RACStream * (^)(id value))block;

產(chǎn)生一個新的stream 每當(dāng)stream發(fā)送一個值時會先詢問block并且訂閱block中返回的stream。
flattenMap 適用于stream中嵌套stream的場景氮兵,例如當(dāng)用戶點(diǎn)擊登錄按鈕后我們需要將用戶名密碼等發(fā)送至服務(wù)器效驗(yàn)裂逐,由服務(wù)器返回效驗(yàn)結(jié)果以判斷用戶名密碼等是否正確。

RACSignal * loginSignal = [self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside];
RACSignal * checkUserSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    // 延時模擬請求
    [[RACScheduler mainThreadScheduler]afterDelay:3 schedule:^{
        [subscriber sendNext:@"success"];
        [subscriber sendCompleted];
    }];
    return nil;
}];
RACSignal * loginResultSignal = [loginSignal flattenMap:^RACStream *(id value) {
    return checkUserSignal;
}];
[loginResultSignal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];

- (instancetype)map:(id (^)(id value))block;

每當(dāng)stream發(fā)送一個value時會將value傳入block產(chǎn)生一個新的value并發(fā)送泣栈。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@" "];
    [subscriber sendNext:@"1"];
    [subscriber sendCompleted];
    return nil;
}] map:^id(NSString * value) {
    if ([value isEqualToString:@" "]) {
        return @"0";
    }
    return value;
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];

- (instancetype)mapReplace:(id)object;

將 stream 發(fā)送的值全部替換為為object


- (instancetype)filter:(BOOL (^)(id value))block;

stream 每產(chǎn)生一個值都傳入block進(jìn)行測試卜高,當(dāng)block返回NO時該值將不會被訂閱者接收到弥姻。


- (instancetype)ignore:(id)innerValue;

stream 每產(chǎn)生一個value進(jìn)行 value != innerValue && [value -isEqual:innerValue] 運(yùn)算,運(yùn)算結(jié)果為YES時訂閱者不會接收到value掺涛。innerValue 可以被設(shè)置為 nil 庭敦。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:nil];
    [subscriber sendNext:@"1"];
    [subscriber sendCompleted];
    return nil;
}]ignore:nil];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
/*
2018-03-28 17:39:59.041 ReactCocoaTest[3000:1590755] 1
2018-03-28 17:39:59.041 ReactCocoaTest[3000:1590755] 1
*/

- (instancetype)reduceEach:(id (^)())reduceBlock;

將stream發(fā)送的RACTuple中的值使用reduceBlock處理為一個值。在方法聲明中并沒有說明reduceBlock的參數(shù)個數(shù)薪缆,使用時注意reduceBlock的參數(shù)個數(shù)要與RACTuple中包含的值的個數(shù)相同秧廉。

RACSignal * signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"11"];
    [subscriber sendCompleted];
    return nil;
}];
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"22"];
    [subscriber sendCompleted];
    return nil;
}];
RACSignal * signal3 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"3"];
    [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
        [subscriber sendNext:@"33"];
        [subscriber sendCompleted];
    }];
    return nil;
}];

[[[RACSignal zip:@[signal1,signal2,signal3]] reduceEach:^id(NSString * a, NSString * b, NSString * c){
    return [NSString stringWithFormat:@"%@ %@ %@",a,b,c];
}] subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];

+ (instancetype)zip:(id<NSFastEnumeration>)streams reduce:(id (^)())reduceBlock;

+zip: 與 -reduceEach:的組合。


- (instancetype)startWith:(id)value;

指定stream的起始值拣帽,當(dāng)訂閱者訂閱stream時會立即收到value所指定的值疼电。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
        [subscriber sendNext:@"1"];
        [subscriber sendCompleted];
    }];
    return nil;
}] startWith:@"0"];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 11:39:17.538975+0800 ReactiveCocoaTest[31885:730340] 0
2018-04-12 11:39:19.540758+0800 ReactiveCocoaTest[31885:730340] 1

- (instancetype)skip:(NSUInteger)skipCount;

跳過指定次數(shù)的值,訂閱者只能接收到第skipCount次之后的值减拭。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        [subscriber sendNext:@"4"];
        [subscriber sendNext:@"5"];
        [subscriber sendCompleted];
    }];
    return nil;
}] skip:3];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 15:26:04.206220+0800 ReactiveCocoaTest[36205:852172] 4
2018-04-12 15:26:04.206473+0800 ReactiveCocoaTest[36205:852172] 5

- (instancetype)take:(NSUInteger)count;

只發(fā)送前count次的值蔽豺。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        [subscriber sendNext:@"4"];
        [subscriber sendNext:@"5"];
        [subscriber sendCompleted];
    }];
    return nil;
}] take:3];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 15:27:04.557102+0800 ReactiveCocoaTest[36338:854896] 1
2018-04-12 15:27:04.557391+0800 ReactiveCocoaTest[36338:854896] 2
2018-04-12 15:27:04.557603+0800 ReactiveCocoaTest[36338:854896] 3

- (instancetype)scanWithStart:(id)startingValue reduce:(id (^)(id running, id next))block;

startingValue:block中running的起始值。
block:依次將stream中發(fā)送的值作為next傳入block并且將上一次block的返回值作為running傳入block峡谊。每一次block返回一個值后會將原來的值替換茫虽。

官方給出的例子
RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
// Contains 1, 3, 6, 10
RACSequence *sums = [numbers scanWithStart:@0 reduce:^(NSNumber *sum, NSNumber *next) {
    return @(sum.integerValue + next.integerValue);
}];
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        [subscriber sendNext:@"4"];
        [subscriber sendNext:@"5"];
        [subscriber sendCompleted];
    }];
    return nil;
}] scanWithStart:@"a" reduce:^id(id running, id next) {
    return [NSString stringWithFormat:@"%@,%@",running,next];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];

2018-04-12 16:35:38.272950+0800 ReactiveCocoaTest[38313:919048] a,1
2018-04-12 16:35:38.273245+0800 ReactiveCocoaTest[38313:919048] a,1,2
2018-04-12 16:35:38.273708+0800 ReactiveCocoaTest[38313:919048] a,1,2,3
2018-04-12 16:35:38.274369+0800 ReactiveCocoaTest[38313:919048] a,1,2,3,4
2018-04-12 16:35:38.274632+0800 ReactiveCocoaTest[38313:919048] a,1,2,3,4,5

- (instancetype)combinePreviousWithStart:(id)start reduce:(id (^)(id previous, id current))reduceBlock;

start:reduceBlock中previous的起始值刊苍。
reduceBlock:依次將stream中上一次發(fā)送的值與當(dāng)前發(fā)送的值分別作為previous和current傳入reduceBlock既们,并得到一個新的值。每一次reduceBlock返回一個值后會將原來的值替換正什。

官方給出的例子
RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
// Contains 1, 3, 5, 7
RACSequence *sums = [numbers combinePreviousWithStart:@0 reduce:^(NSNumber *previous, NSNumber *next) {
    return @(previous.integerValue + next.integerValue);
}];
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
        [subscriber sendNext:@"1"];
        [subscriber sendNext:@"2"];
        [subscriber sendNext:@"3"];
        [subscriber sendNext:@"4"];
        [subscriber sendNext:@"5"];
        [subscriber sendCompleted];
    }];
    return nil;
}] combinePreviousWithStart:@"a" reduce:^id(id previous, id current) {
    return [NSString stringWithFormat:@"%@,%@",previous,current];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 16:41:54.005897+0800 ReactiveCocoaTest[38662:929686] a,1
2018-04-12 16:41:54.006375+0800 ReactiveCocoaTest[38662:929686] 1,2
2018-04-12 16:41:54.006617+0800 ReactiveCocoaTest[38662:929686] 2,3
2018-04-12 16:41:54.006957+0800 ReactiveCocoaTest[38662:929686] 3,4
2018-04-12 16:41:54.008215+0800 ReactiveCocoaTest[38662:929686] 4,5

- (instancetype)takeUntilBlock:(BOOL (^)(id x))predicate;

每當(dāng)stream產(chǎn)生一個值都會詢問predicate啥纸,當(dāng)predicate返回YES當(dāng)前值以及后續(xù)值不會被訂閱者接收到。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"3"];
    [subscriber sendNext:@"4"];
    [subscriber sendNext:@"5"];
    [subscriber sendCompleted];
    return nil;
}] takeUntilBlock:^BOOL(id x) {
    return [x isEqualToString:@"3"];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 16:54:04.421888+0800 ReactiveCocoaTest[39002:945018] 1
2018-04-12 16:54:04.422144+0800 ReactiveCocoaTest[39002:945018] 2

- (instancetype)takeWhileBlock:(BOOL (^)(id x))predicate;

每當(dāng)stream產(chǎn)生一個值都會詢問predicate婴氮,當(dāng)predicate返回NO當(dāng)前值以及后續(xù)值不會被訂閱者接收到斯棒。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"3"];
    [subscriber sendNext:@"4"];
    [subscriber sendNext:@"5"];
    [subscriber sendCompleted];
    return nil;
}] takeWhileBlock:^BOOL(id x) {
    return [x isEqualToString:@"1"];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 16:57:01.353910+0800 ReactiveCocoaTest[39611:952168] 1

- (instancetype)skipUntilBlock:(BOOL (^)(id x))predicate;

每當(dāng)stream產(chǎn)生一個值都會詢問predicate,當(dāng)predicate返回YES當(dāng)前值以及后續(xù)值才會被訂閱者接收到主经。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"3"];
    [subscriber sendNext:@"4"];
    [subscriber sendNext:@"5"];
    [subscriber sendCompleted];
    return nil;
}] skipUntilBlock:^BOOL(id x) {
    return [x isEqualToString:@"3"];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 17:00:28.968933+0800 ReactiveCocoaTest[39904:958633] 3
2018-04-12 17:00:28.969232+0800 ReactiveCocoaTest[39904:958633] 4
2018-04-12 17:00:28.969613+0800 ReactiveCocoaTest[39904:958633] 5

- (instancetype)skipWhileBlock:(BOOL (^)(id x))predicate;

每當(dāng)stream產(chǎn)生一個值都會詢問predicate荣暮,當(dāng)predicate返回NO當(dāng)前值以及后續(xù)值才會被訂閱者接收到。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"3"];
    [subscriber sendNext:@"4"];
    [subscriber sendNext:@"5"];
    [subscriber sendCompleted];
    return nil;
}] skipWhileBlock:^BOOL(id x) {
    return [x isEqualToString:@"1"];
}];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 17:13:25.548610+0800 ReactiveCocoaTest[40829:978359] 2
2018-04-12 17:13:25.548842+0800 ReactiveCocoaTest[40829:978359] 3
2018-04-12 17:13:25.549123+0800 ReactiveCocoaTest[40829:978359] 4
2018-04-12 17:13:25.549322+0800 ReactiveCocoaTest[40829:978359] 5

- (instancetype)distinctUntilChanged;

每當(dāng)stream產(chǎn)生一個新的值都會與上一次產(chǎn)生的值進(jìn)行 lastValue == x || [x isEqual:lastValue] 判斷罩驻,如果返回YES則訂閱者不會接收到值穗酥。

RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"2"];
    [subscriber sendNext:@"1"];
    [subscriber sendNext:@"1"];
    [subscriber sendCompleted];
    return nil;
}] distinctUntilChanged];
[signal subscribeNext:^(id x) {
    NSLog(@"%@",x);
}];
2018-04-12 17:16:13.919028+0800 ReactiveCocoaTest[40996:981741] 1
2018-04-12 17:16:13.919383+0800 ReactiveCocoaTest[40996:981741] 2
2018-04-12 17:16:13.919676+0800 ReactiveCocoaTest[40996:981741] 1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惠遏,隨后出現(xiàn)的幾起案子砾跃,更是在濱河造成了極大的恐慌,老刑警劉巖节吮,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抽高,死亡現(xiàn)場離奇詭異,居然都是意外死亡透绩,警方通過查閱死者的電腦和手機(jī)翘骂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門壁熄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碳竟,你說我怎么就攤上這事请毛。” “怎么了瞭亮?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵方仿,是天一觀的道長。 經(jīng)常有香客問我统翩,道長仙蚜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任厂汗,我火速辦了婚禮委粉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娶桦。我一直安慰自己贾节,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布衷畦。 她就那樣靜靜地躺著栗涂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祈争。 梳的紋絲不亂的頭發(fā)上斤程,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機(jī)與錄音菩混,去河邊找鬼忿墅。 笑死,一個胖子當(dāng)著我的面吹牛沮峡,可吹牛的內(nèi)容都是我干的疚脐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼邢疙,長吁一口氣:“原來是場噩夢啊……” “哼棍弄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起秘症,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤照卦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乡摹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體役耕,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年聪廉,在試婚紗的時候發(fā)現(xiàn)自己被綠了瞬痘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片故慈。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖框全,靈堂內(nèi)的尸體忽然破棺而出察绷,到底是詐尸還是另有隱情,我是刑警寧澤津辩,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布拆撼,位于F島的核電站,受9級特大地震影響喘沿,放射性物質(zhì)發(fā)生泄漏闸度。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一蚜印、第九天 我趴在偏房一處隱蔽的房頂上張望莺禁。 院中可真熱鬧,春花似錦窄赋、人聲如沸哟冬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晶乔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間红符,已是汗流浹背青柄。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工伐债, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人致开。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓峰锁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親双戳。 傳聞我的和親對象是個殘疾皇子虹蒋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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