ReactiveCocoa2.5基礎(chǔ)知識(shí)

ReactiveCocoa2.5基礎(chǔ)知識(shí)

[toc]

ReactiveCocoa 是一個(gè) iOS 中的函數(shù)式響應(yīng)式編程框架,本文中簡(jiǎn)稱RAC崭篡。在開(kāi)發(fā) GitHub for Mac 過(guò)程中的一個(gè)副產(chǎn)品,它提供了一系列用來(lái)組合和轉(zhuǎn)換值流的 API 。本文只是記錄自己學(xué)到ReactiveCocoa的筆記觉壶。

ReactiveCocoa核心組件

信號(hào)源

RACStream 有兩個(gè)派生類

RACSequence :基于空間的數(shù)據(jù)流(在RAC中很少使用)
創(chuàng)建
    RACSequence *sequence1 = [RACSequence return:@1];
    NSLog(@"%@",sequence1.head);
    // 輸出:1
    RACSequence *sequence2 = [RACSequence sequenceWithHeadBlock:^id{
        return @2;
    } tailBlock:^RACSequence *{
        return sequence1;
    }];
    NSLog(@"%@ %@",sequence2.head,sequence2.tail.head);
    // 輸出:2 1
    RACSequence *sequence3 = @[@4,@5,@6,@7].rac_sequence;
     for (id value in concatSquence) {
          NSLog(@"%@",value);
    }
    // 輸出:4
    // 輸出:5
    // 輸出:6
    // 輸出:7
變換
    RACSequence *mapSrquence = [sequence1 map:^id(NSNumber *value) {
            return @(value.integerValue *3); // 1 * 3
        }];
        NSLog(@"%@",mapSrquence.head);
        // 輸出:3
// concat:合并吮廉,目的:有兩部分?jǐn)?shù)據(jù),想讓上部分先執(zhí)行入挣,完了之后再讓下部分執(zhí)行(都可獲取值)
    RACSequence *concatSquence = [sequence2 concat:mapSrquence];
    for (id value in concatSquence) {
        NSLog(@"%@",value);
    }
    // 輸出:2
    // 輸出:1
    // 輸出:3

    concatSquence: 2 1 3
    sequence3    : 4 5 6 7
    RACSequence *zipSquence = [RACSequence zip:@[concatSquence,sequence3]];
    
遍歷
for (RACTuple *tuple in zipSquence) {
        NSLog(@"%@---%@",tuple.first,tuple.second);
    }
    // 輸出:2---4
    // 輸出:1---5
    // 輸出:3---6
RACSignal :基于時(shí)間的數(shù)據(jù)流
1.使用基礎(chǔ)
- 單元信號(hào)
    RACSignal *signal1 = [RACSignal return:@1];
    RACSignal *signal2 = [RACSignal error:errorObject];
    RACSignal *signal3 = [RACSignal empty];
    RACSignal *signal4 = [RACSignal never];
- 動(dòng)態(tài)信號(hào)
    RACSignal *signal5 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        // 如果出現(xiàn)錯(cuò)誤,sendCompleted就會(huì)失效
//        [subscriber sendError:errorObject];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
        }];
    }];
- Cocoa橋接
    // 監(jiān)聽(tīng)
    RACSignal *signal6 = [view rac_signalForSelector:@selector(setFrame)];
    // 事件點(diǎn)擊
    RACSignal *signal7 = [button rac_signalForControlEvents:UIControlEventTouchUpInside];
    // dealloc
    RACSignal *signal8 = [view rac_willDeallocSignal];
    // KVO
    RACSignal *signal9 = RACObserve(view, backgroundColor);
- 信號(hào)變換
    RACSignal *signal10 = [signal1 map:^id(NSString *value) {
        return [value substringFromIndex:1];
    }];
- 序列轉(zhuǎn)換
  RACSequence *sequence = [RACSequence return:@1];
    RACSignal *signal11 = sequence.signal;
2.訂閱一個(gè)信號(hào)的方式

2.1 ) 訂閱方法

// 有三種參數(shù)方法
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock;
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock;
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock;
 example:
 [signal11 subscribeNext:^(id x) {
        NSLog(@"%@",x);
    } error:^(NSError *error) {
        NSLog(@"error");
    } completed:^{
        NSLog(@"finished");
    }];

2.2 ) 綁定

RAC(view,backgroundColor) = signal10;

2.3 ) Cocoa橋接

// rac_liftSelector: 相當(dāng)于多線程組;所有信號(hào)請(qǐng)求完成之后再執(zhí)行方法归粉,只需把三個(gè)結(jié)果傳出去即可
[view rac_liftSelector:@selector(updateUIWithR1:r2:) withSignals:signal1,signal3, nil];
[view rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[signal1,signal1]];
[view rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalOfArguments:signal1];
3.單個(gè)信號(hào)的變換

3.1 ) 值操作

  • Map:映射,目的:把原始值value映射成一個(gè)新值


   RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       [subscriber sendNext:@1];
       [subscriber sendNext:@2];
       [subscriber sendNext:@3];
       [subscriber sendCompleted];
       return nil;
   }];
   RACSignal *signalB = [signalA map:^id(NSNumber *value) {
       return @(value.integerValue * 3);
   }];
   [signalB subscribeNext:^(id x) {
       NSLog(@"%@",x);
   }];
   // 輸出:3
   // 輸出:6
   // 輸出:9
  • mapReplace:Map簡(jiǎn)化操作漏峰,只返回一個(gè)相同的信號(hào)
RACSignal *signalC = [signalA mapReplace:@8];
   [signalC subscribeNext:^(id x) {
       NSLog(@"%@",x);
   }];
   // 輸出:8
   // 輸出:8
   // 輸出:8
  • reduceEach:Map的變體糠悼,當(dāng) signalA 的值事件包裹的數(shù)據(jù)是 RACTuple 類型時(shí),才可以使用該操作


RACSignal *signalD = [signalA reduceEach:^id(NSNumber *num1 , NSNumber *num2){
        return @([num1 intValue] + [num2 intValue]);
    }];
  • not:需要傳入的值都是NSNumber類型的,不是NSNumber類型會(huì)報(bào)錯(cuò)
  • not操作會(huì)把每個(gè)NSNumber按照BOOL的規(guī)則浅乔,取非倔喂,當(dāng)成新信號(hào)的值。
- (RACSignal *)not {
    return [[self map:^(NSNumber *value) {
        NSCAssert([value isKindOfClass:NSNumber.class], @"-not must only be used on a signal of NSNumbers. Instead, got: %@", value);
        return @(!value.boolValue);
    }] setNameWithFormat:@"[%@] -not", self.name];
}
  • and操作需要原信號(hào)的每個(gè)信號(hào)都是元組RACTuple類型的靖苇,因?yàn)橹挥羞@樣席噩,RACTuple類型里面的每個(gè)元素的值才能進(jìn)行&運(yùn)算。
  • and操作里面有3處斷言顾复。第一處班挖,判斷入?yún)⑹遣皇窃MRACTuple類型的。第二處芯砸,判斷RACTuple類型里面至少包含一個(gè)NSNumber萧芙。第三處,判斷RACTuple里面是否都是NSNumber類型假丧,有一個(gè)不符合双揪,都會(huì)報(bào)錯(cuò)。
- (RACSignal *)and {
    return [[self map:^(RACTuple *tuple) {
        NSCAssert([tuple isKindOfClass:RACTuple.class], @"-and must only be used on a signal of RACTuples of NSNumbers. Instead, received: %@", tuple);
        NSCAssert(tuple.count > 0, @"-and must only be used on a signal of RACTuples of NSNumbers, with at least 1 value in the tuple");
        return @([tuple.rac_sequence all:^(NSNumber *number) {
            NSCAssert([number isKindOfClass:NSNumber.class], @"-and must only be used on a signal of RACTuples of NSNumbers. Instead, tuple contains a non-NSNumber value: %@", tuple);
            return number.boolValue;
        }]);
    }] setNameWithFormat:@"[%@] -and", self.name];
}
  • or操作的實(shí)現(xiàn)和and操作的實(shí)現(xiàn)大體類似包帚。3處斷言的作用和and操作完全一致渔期,這里就不再贅述了。or操作的重點(diǎn)在any函數(shù)的實(shí)現(xiàn)上。or操作的入?yún)⒁脖仨毷荝ACTuple類型的疯趟。
- (RACSignal *)or {
    return [[self map:^(RACTuple *tuple) {
        NSCAssert([tuple isKindOfClass:RACTuple.class], @"-or must only be used on a signal of RACTuples of NSNumbers. Instead, received: %@", tuple);
        NSCAssert(tuple.count > 0, @"-or must only be used on a signal of RACTuples of NSNumbers, with at least 1 value in the tuple");
        return @([tuple.rac_sequence any:^(NSNumber *number) {
            NSCAssert([number isKindOfClass:NSNumber.class], @"-or must only be used on a signal of RACTuples of NSNumbers. Instead, tuple contains a non-NSNumber value: %@", tuple);
            return number.boolValue;
        }]);
    }] setNameWithFormat:@"[%@] -or", self.name];
}
  • 這里也有2個(gè)斷言拘哨,第一個(gè)是確保傳入的參數(shù)是RACTuple類型,第二個(gè)斷言是確保元組RACTuple里面的元素各種至少是2個(gè)信峻。因?yàn)橄旅嫒?shù)是直接從1號(hào)位開(kāi)始取的倦青。
  • reduceApply做的事情和reduceEach基本是等效的,只不過(guò)變換規(guī)則的block閉包一個(gè)是外部傳進(jìn)去的盹舞,一個(gè)是直接打包在每個(gè)信號(hào)元組RACTuple中第0位中产镐。
- (RACSignal *)reduceApply {
    return [[self map:^(RACTuple *tuple) {
        NSCAssert([tuple isKindOfClass:RACTuple.class], @"-reduceApply must only be used on a signal of RACTuples. Instead, received: %@", tuple);
        NSCAssert(tuple.count > 1, @"-reduceApply must only be used on a signal of RACTuples, with at least a block in tuple[0] and its first argument in tuple[1]");
        // We can't use -array, because we need to preserve RACTupleNil
        NSMutableArray *tupleArray = [NSMutableArray arrayWithCapacity:tuple.count];
        for (id val in tuple) {
            [tupleArray addObject:val];
        }
        RACTuple *arguments = [RACTuple tupleWithObjectsFromArray:[tupleArray subarrayWithRange:NSMakeRange(1, tupleArray.count - 1)]];
        return [RACBlockTrampoline invokeBlock:tuple[0] withArguments:arguments];
    }] setNameWithFormat:@"[%@] -reduceApply", self.name];
}
// 舉個(gè)例子
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber){
                              id block = ^id(NSNumber *first,NSNumber *second,NSNumber *third) {
                                  return @(first.integerValue + second.integerValue * third.integerValue);
                              };
                              [subscriber sendNext:RACTuplePack(block,@1 , @3 , @5)];
                              [subscriber sendNext:RACTuplePack((id)(^id(NSNumber *x){return @(x.intValue * 10);}),@10,@20,@30)];
                              [subscriber sendCompleted];
                              return [RACDisposable disposableWithBlock:^{
                              }];
                          }];
    RACSignal *signalB = [signalA reduceApply];
    [signalB subscribeNext:^(id x) {
                NSLog(@"%@",x);
            }];
    // 輸出:16 = 1 + 3*5
    // 輸出:100 = 10 * 10
  • materialize把信號(hào)包裝成RACEvent類型。
- (RACSignal *)materialize {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [self subscribeNext:^(id x) {
            [subscriber sendNext:[RACEvent eventWithValue:x]];
        } error:^(NSError *error) {
            [subscriber sendNext:[RACEvent eventWithError:error]];
            [subscriber sendCompleted];
        } completed:^{
            [subscriber sendNext:RACEvent.completedEvent];
            [subscriber sendCompleted];
        }];
    }] setNameWithFormat:@"[%@] -materialize", self.name];
}
  • dematerialize操作是materialize的逆向操作踢步。它會(huì)把包裝成RACEvent信號(hào)重新還原為正常的值信號(hào)癣亚。
- (RACSignal *)dematerialize {
    return [[self bind:^{
        return ^(RACEvent *event, BOOL *stop) {
            switch (event.eventType) {
                case RACEventTypeCompleted:
                    *stop = YES;
                    return [RACSignal empty];
                case RACEventTypeError:
                    *stop = YES;
                    return [RACSignal error:event.error];
                case RACEventTypeNext:
                    return [RACSignal return:event.value];
            }
        };
    }] setNameWithFormat:@"[%@] -dematerialize", self.name];
}

3.2 ) 數(shù)量操作


  • Filter:過(guò)濾
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"ab"];
        [subscriber sendNext:@"hello"];
        [subscriber sendNext:@"world"];
        [subscriber sendNext:@"123"];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signalC = [signalA filter:^BOOL(NSString *value) {
        return value.length > 3;
    }];
    [signalC subscribeNext:^(id x) { 
        NSLog(@"%@",x);
    }];
// 輸出:hello
// 輸出:world
  • Ignore:忽略
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"Ab"];
        [subscriber sendNext:@"hello"];
        [subscriber sendNext:@"world"];
        [subscriber sendNext:@"123"];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signalB = [signalA filter:^BOOL(NSString *value) {
        return ![value isEqual:@"ab"];
    }];
    [signalB subscribeNext:^(id x) { 
        NSLog(@"%@",x);
    }];
// 輸出:hello
// 輸出:world
// 輸出:123
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"Ab"];
        [subscriber sendNext:@"hello"];
        [subscriber sendNext:@"world"];
        [subscriber sendNext:@"123"];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signalC = [signalA ignore:@"ab"];
    [signalC subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
// 輸出:hello
// 輸出:world
// 輸出:123
  • ignoreValues:忽略所有的值

  • distinctUntilChanged:讀取所有的值

  • Take:取值的數(shù)量


  • Skip:跳過(guò)


  • StartWith:初始位置添加


  • Repeat:重復(fù)說(shuō)(一直不停止)


  • Retry:遇到錯(cuò)誤繼續(xù)嘗試


  • 副作用

  • DoNext:副作用操作,做一些事情

- (RACSignal *)doError:(void (^)(NSError *error))block;
- (RACSignal *)doCompleted:(void (^)(void))block;
- (RACSignal *)initially:(void (^)(void))block;
- (RACSignal *)finally:(void (^)(void))block;
  • Collect收集源信號(hào)的所有sendNext事件获印,直到源信號(hào)發(fā)出sendComplete事件述雾,才將收集好的sendNext事件發(fā)出去


  • Aggregate折疊函數(shù),和Scan這兩個(gè)操作有些類似蓬豁,但明顯有區(qū)別绰咽,前者改變了事件流的事件數(shù)量,后者沒(méi)有


  • Scan每次計(jì)算結(jié)果都會(huì)給到一個(gè)加和



    3.3 ) 時(shí)間操作

  • Delay延遲


  • Throttle:閥門(mén)



    3.4 ) 組合操作

  • Concat:連接


  • Merge:匯合


RACSignal *signalC = [signalA merge:signalB];
RACSignal *signalD = [RACSignal merge:@[signalA,signalB]];
RACSignal *signalE = [RACSignal merge:RACTuplePack(signalA,signalB)];
  • zip:拉鏈地粪,目的:把兩個(gè)信號(hào)壓縮成一個(gè)信號(hào)取募,并且把兩個(gè)信號(hào)的內(nèi)容合并成一個(gè)元組


RACSignal *signalC = [signalA zipWith:signalB];
RACSignal *signalD = [RACSignal zip:@[signalA,signalB]];
RACSignal *signalE = [RACSignal zip:RACTuplePack(signalA,signalB)];
  • CombineLatest:和數(shù)學(xué)中的邏輯與(&&)的概念是一樣的择浊,只有兩個(gè)兩個(gè)信號(hào)同時(shí)發(fā)送了sendNext事件宁仔,才會(huì)觸發(fā)


RACSignal *signalC = [signalA combineLatestWith:signalB];
RACSignal *signalD = [RACSignal combineLatest:@[signalA,signalB]];
  • Sample:采樣


  • TakeUntil:當(dāng)下一個(gè)信號(hào)傳遞的時(shí)候停止訂閱信號(hào)


  • TakeUntilReplacement:當(dāng)下一個(gè)信號(hào)傳遞的時(shí)候停止訂閱信號(hào),并返回加和下個(gè)信號(hào)


兩者的區(qū)別
Pull-driver vs Push-driver

例子:看電影
Sequence:看本地下載的電影,突然想上廁所闯第,可以暫停质礼,上完廁所回來(lái)再看(觀看者決定)
Signal:在線看電影旺聚,不管你看不看電影一直都在播放(發(fā)送者決定)

Data vs Event

Sequence: 任何ID類型的數(shù)據(jù)(值)
Signal:基于信號(hào)(值,錯(cuò)誤眶蕉,終止砰粹,中斷)

訂閱者

RACSubscriber

訂閱過(guò)程

對(duì)于訂閱過(guò)程不了解可以查看這三篇博客
細(xì)說(shuō)ReactiveCocoa的冷信號(hào)與熱信號(hào)(一)
細(xì)說(shuō)ReactiveCocoa的冷信號(hào)與熱信號(hào)(二)
細(xì)說(shuō)ReactiveCocoa的冷信號(hào)與熱信號(hào)(三)

RACSignal *signal5 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"dispose");
        }];
    }];
    RACDisposable *disposable = [signal5 subscribeNext:^(id x) {
        NSLog(@"%@",x);
    } error:^(NSError *error) {
        NSLog(@"error");
    } completed:^{
        NSLog(@"finished");
    }];
    [disposable dispose];

調(diào)度器

RACScheduler

RACSchedulerReactiveCocoa 中就是扮演著調(diào)度器的角色,本質(zhì)上造挽,它就是用 GCD 的串行隊(duì)列來(lái)實(shí)現(xiàn)的碱璃,并且支持取消操作。是的饭入,在 ReactiveCocoa 中嵌器,并沒(méi)有使用到 NSOperationQueueNSRunloop 等技術(shù),RACScheduler 也只是對(duì) GCD 的簡(jiǎn)單封裝而已谐丢。

清潔工

RACDisposable

RACDisposableReactiveCocoa 中就充當(dāng)著清潔工的角色爽航,它封裝了取消和清理一次訂閱所必需的工作蚓让。它有一個(gè)核心的方法 -dispose ,調(diào)用這個(gè)方法就會(huì)執(zhí)行相應(yīng)的清理工作讥珍,這有點(diǎn)類似于 NSObject-dealloc 方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末历极,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子串述,更是在濱河造成了極大的恐慌执解,老刑警劉巖寞肖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纲酗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡新蟆,警方通過(guò)查閱死者的電腦和手機(jī)觅赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琼稻,“玉大人吮螺,你說(shuō)我怎么就攤上這事∨练” “怎么了鸠补?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嘀掸。 經(jīng)常有香客問(wèn)我紫岩,道長(zhǎng),這世上最難降的妖魔是什么睬塌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任泉蝌,我火速辦了婚禮,結(jié)果婚禮上揩晴,老公的妹妹穿的比我還像新娘勋陪。我一直安慰自己,他們只是感情好硫兰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布诅愚。 她就那樣靜靜地躺著,像睡著了一般劫映。 火紅的嫁衣襯著肌膚如雪违孝。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天苏研,我揣著相機(jī)與錄音等浊,去河邊找鬼。 笑死摹蘑,一個(gè)胖子當(dāng)著我的面吹牛筹燕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼撒踪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼过咬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起制妄,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤掸绞,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后耕捞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體衔掸,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年俺抽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敞映。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡磷斧,死狀恐怖振愿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弛饭,我是刑警寧澤冕末,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站侣颂,受9級(jí)特大地震影響档桃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜横蜒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一胳蛮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丛晌,春花似錦仅炊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至谋逻,卻和暖如春呆馁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毁兆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工浙滤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人气堕。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓纺腊,卻偏偏與公主長(zhǎng)得像畔咧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揖膜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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