ReactiveCocoa 學(xué)習(xí)筆記(一)

MVVM

  • MVC ---> Model View Controller ----> 復(fù)雜應(yīng)用 ---> Massive View Controller(重量級視圖控制器) 沸柔。所以需要給給視圖控制器瘦身.
  • MVVM 是 MVC 模式的一種演進(jìn)刨摩,主要解決了ViewController過于臃腫帶來的不易維護(hù)和測試問題伍玖。
  • view 是一個(gè)殼 坤按,不關(guān)心數(shù)據(jù)姓迅,所呈現(xiàn)的內(nèi)容都由 ViewController來提供干奢。但是又不是直接去溝通viewmodel罐农,而是用viewController來做中間的協(xié)調(diào)者汗侵。
  • viewController 管理view和viewModel崔拥,當(dāng)VC初始化的時(shí)候通過viewModel中的方法去取數(shù)據(jù)极舔。盡量不涉及業(yè)務(wù)邏輯,讓 ViewModel 去做這些事情.只是一個(gè)中間人链瓦,接收 View 的事件拆魏、調(diào)用 ViewModel 的方法盯桦、響應(yīng) ViewModel 的變化。
  • 好處:可以讓Controller更加簡單和輕便渤刃,而且ViewModel相對獨(dú)立拥峦,也更加方便測試和重用

Controller

  • 可以被看成View
  • 處理布局、動畫卖子、接收系統(tǒng)事件略号、展示UI

View-Model

  • 代表應(yīng)用程序UI狀態(tài)的特殊類型的模型
  • 獲取原始數(shù)據(jù), 運(yùn)用邏輯, 并處理成 view (controller) 的展示數(shù)據(jù).
  • 不能包含 View,不然就跟 View 產(chǎn)生了耦合洋闽,不方便復(fù)用和測試玄柠。
  • 它(通常通過屬性)暴露給視圖控制器需要知道的僅關(guān)于顯示視圖工作的信息(理想地你不會暴漏你的 data-model 對象). 它還負(fù)責(zé)對上游數(shù)據(jù)的修改(比如更新模型/數(shù)據(jù)庫, API POST 調(diào)用).
  • 富有邏輯和轉(zhuǎn)換數(shù)據(jù)并將結(jié)果存到屬性的功能. 理想上相同的輸入(比如網(wǎng)絡(luò)服務(wù)響應(yīng))將會導(dǎo)出相同的輸出(屬性的值). 這意味著盡可能多地消除由”應(yīng)用世界”剩余部分帶來的可能影響輸出的因素。
  • ViewModel 之間可以有依賴诫舅。比如VC的VM和tableViewCell的VM羽利。
  • ViewModel 避免過于臃腫,不然維護(hù)起來也是個(gè)問題.
  • 不對視圖控制器以任何形式直接起作用或直接通知其變化.

當(dāng) view-model 的共有屬性發(fā)生變化 更新視圖方法

  • 用對應(yīng)的 view-model 來初始化視圖控制器

     UIViewController *controller =[[UIViewController alloc] initWithViewModel:  ViewModel];
    
  • 無法在初始化時(shí)將 view-model 傳入 比如在 storyboard segue 或 cell dequeuing 的情況下,這時(shí)需要在視圖(控制器)中暴露一個(gè)公有可寫的 view-model 屬性

    UITableViewCell *cell =[self.tableView dequeueReusableCellWithIdentifier: @"cell" forIndexPath: indexPath];
    // 給暴露出來的viewmodl賦值
    cell.viewModel = self.viewModel. tweets[indexPath. row];
    
  • 可以在鉤子程序調(diào)用前傳入 view-model, 比如 init 和 viewDidLoad, 我們可以從view-model 的屬性初始化所有 UI 元素的狀態(tài).

    //dontDoThis1.m 
    - (id) initWithViewModel:(MYTwitterLookupViewModel *) viewModel {
        self = [super init];
        if (!self) return nil;
        _viewModel = viewModel;
        return self;
    }
    - (void) viewDidLoad {
        [super viewDidLoad];
        _goButton.enabled = viewModel.isUsernameValid;
        _goButton.alpha = viewModel.isUsernameValid ? 1 : 0.5;
        // etc
    }
    
    

MVVM實(shí)現(xiàn)方式

  • Delegate
  • KVO
  • Block
  • ReactiveCocoa

MVVM還有一個(gè)很重要的概念是 data binding刊懈,view的呈現(xiàn)需要data铐伴,這個(gè)data就是由ViewModel提供的,將view的data與ViewModel的data綁定后俏讹,將來雙方的數(shù)據(jù)只要一方有變化当宴,另一方就能收到。這里有Github 開源的一個(gè)ViewModel Base Class泽疆。

函數(shù)響應(yīng)式式編程

  • Functional Reactive Programming(以下簡稱FRP)是一種響應(yīng)變化的編程范式户矢。
  • FRP提供了一種信號機(jī)制來實(shí)現(xiàn)這樣的效果,通過信號來記錄值的變化殉疼。信號可以被疊加梯浪、分割或合并。通過對信號的組合瓢娜,就不需要去監(jiān)聽某個(gè)值或事件挂洛。
  • 在 iOS/Objective-C 中達(dá)到純函數(shù)水平是很棘手的(Swift 提供了一些附加的函數(shù)性, 這會讓我們更接近).
  • 簡單函數(shù)為例子, 它們可能接受一兩個(gè)參數(shù)并輸出一個(gè)結(jié)果. 數(shù)據(jù)輸入, 數(shù)據(jù)輸出.這個(gè)函數(shù)可能是做一些數(shù)學(xué)運(yùn)算或是將姓和名結(jié)合到一起. 無論應(yīng)用的其他地方發(fā)生啥, 這個(gè)函數(shù)總是對相同的輸入產(chǎn)生相同的輸出. 這就是函數(shù)式方面
  • view-model 仍然只是一個(gè)對象, 而不用維護(hù)一些狀態(tài)(否則它將不會是你視圖中非常好用的模型了. )但你仍該努力將盡可能多的邏輯移到無狀態(tài)的函數(shù)”值”中. 再重復(fù)一次, Swift在這方面比 Objective-C 更加可行.
  • 單元測試方便眠砾,bug 數(shù)量隨著狀態(tài)數(shù)遞減虏劲,避免了視圖控制器的復(fù)雜性

ReactiveCocoa

  • 在iOS平臺上對FRP的實(shí)現(xiàn)。
  • 核心:信號褒颈,用RACSignal實(shí)現(xiàn)柒巫。

RACSignal

  • RACSignal是數(shù)據(jù)流,可以被綁定和傳遞.
  • RACSignal (信號)是RAC的構(gòu)造單元谷丸,作用就是可以預(yù)先運(yùn)用邏輯并構(gòu)建處理(陳述性)堡掏,而不是非要等到事情發(fā)生后才處理(命令式)。
  • RACSignal可以把所有這些異步方法(代理刨疼、block泉唁、通知鹅龄、KVO、target/action等)統(tǒng)一到一個(gè)接口下亭畜。[圖片上傳失敗...(image-6223bb-1510888578514)]
  • 訂閱后砾层,當(dāng)訂閱者發(fā)生變化,RACSignal會向訂閱者一次發(fā)送0或多個(gè)載有數(shù)值的“next”事件贱案,后面跟著一個(gè)“complete”或“error”事件。

常見關(guān)鍵詞

  • createSignal:創(chuàng)建信號
  • subscriber 有了訂閱者止吐,傳送給訂閱者
  • filter:過濾宝踪,符合條件才向下執(zhí)行。
  • defer : 將代碼的創(chuàng)建推遲到信號被訂閱
  • concat: 連接信號,第一個(gè)信號必須發(fā)送完成碍扔,第二個(gè)信號才會被激活
  • map : 修改/映射,將信號內(nèi)容轉(zhuǎn)換瘩燥。把信號改成需要的類型。
  • takeUtil : signalA takeUntil:signalB 當(dāng)signalB激活之后,停止signalA 的訂閱
  • combineLatest:reduce:多個(gè)信號合成成一個(gè)新的信號不同,只要其中一個(gè)有響應(yīng)厉膀,這個(gè)新的信號就會得到這個(gè)響應(yīng)。
  • combine:疊加
  • chain:串聯(lián)
    combineLatest:reduce
RAC(self.myButton, enabled) = [RACSignal combineLatest:@[self.usernameField.rac_textSignal, self.passwordField.rac_textSignal] reduce:^id(NSString *userName, NSString *password) {
    //如果用戶名和密碼框的長度都超過6二拐,提交按鈕就enable
    return @(userName.length >= 6 && password.length >= 6);
}];

RACObserve(TARGET, KEYPATH)

  • 參數(shù):
    • TARGET:要觀察的對象
    • KEYPATH: 要觀察的那個(gè)對象某屬性的keypath
  • RACObserve 會創(chuàng)建一個(gè)信號, 一旦它有了訂閱者, 它就立刻發(fā)送那個(gè)屬性的當(dāng)前值, 并發(fā)送那個(gè)屬性在這之后的任何變化服鹅。
//監(jiān)聽button點(diǎn)擊事件
[[_myButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *button){
       NSLog(@"點(diǎn)擊了button");
}];
//監(jiān)聽textView.text
[[_myTextFiled rac_textSignal]subscribeNext:^(NSString * _Nullable x) {
       NSLog(@"x---%@",x);
}];

注意: RAC 只處理對象, 而不處理像 BOOL 這樣的原始值. 不過不用擔(dān)心, RAC 通常會幫你這些轉(zhuǎn)換.

  • 宏 RAC(TARGET, ...)與 宏RACObserve(TARGET, KEYPATH) 相同
    • RAC(TARGET, ...) 想要與即將到來的值綁定的對象和參數(shù)

轉(zhuǎn)換數(shù)據(jù)流

  • map 方法:返回的是一個(gè)對象。

    //將viewModel的isUsernameValid與myButton的enadbled和backgroundColor綁定百新。
    RACSignal *userNameIsValidSignal = RACObserve(self.viewModel, isUsernameValid);
    RAC(self.myButton,highlighted) = userNameIsValidSignal;
    RAC(self.myButton,backgroundColor) = [userNameIsValidSignal map:^id _Nullable(NSNumber*  _Nullable value) {
    return value.boolValue ? [UIColor redColor] : [UIColor blueColor];
        }];
    

RAC的大統(tǒng)一


在 RAC 的文檔和一些介紹 RAC 的 Keynote 資料里面我們可以看到說 RACSignal 可以來替代 Delegate企软、 Block Callbacks、Target Action饭望、KVO仗哨、Notifications。因?yàn)樗鼈儽举|(zhì)上都是值的變化(Values over time)铅辞。


image.png

KVO
RAC可以用來監(jiān)測屬性的改變厌漂,這點(diǎn)跟KVO很像,不過使用了block斟珊,而不是-observeValueForKeyPath:ofObject:change:context:

[RACAble(self.username) subscribeNext:^(NSString *newName) {
    NSLog(@"%@", newName);
}];

使用起來是不是比KVO舒服多了苇倡。比KVO更加強(qiáng)大的是信號可以被鏈起來(chain)

// 只有當(dāng)名字以'j'開頭,才會被記錄
[[RACAble(self.username)
   filter:^(NSString *newName) {
       return [newName hasPrefix:@"j"];
   }]
   subscribeNext:^(NSString *newName) {
       NSLog(@"%@", newName);
   }];

UI Event
RAC還為系統(tǒng)UI提供了很多category囤踩,來方便消息的創(chuàng)建和傳遞雏节,比如按鈕被點(diǎn)擊或文本框有改動等等。如果有subscriber的話高职,會自動觸發(fā)钩乍。
比如:self.usernametextField.rac_textSignal

Network Request && Async work
這些可以通過自定義信號,也就是RACSubject(繼承自RACSignal怔锌,可以理解為自由度更高的signal)來搞定.

//比如一個(gè)異步網(wǎng)絡(luò)操作寥粹,可以返回一個(gè)subject变过,然后將這個(gè)subject綁定到一個(gè)subscriber或另一個(gè)信號
- (void)doTest
{
    RACSubject *subject = [self doRequest];
    
    [subject subscribeNext:^(NSString *value){
        NSLog(@"value:%@", value);
    }];
}

- (RACSubject *)doRequest
{
    RACSubject *subject = [RACSubject subject];
    // 模擬2秒后得到請求內(nèi)容
    // 只觸發(fā)1次
    // 盡管subscribeNext什么也沒做,但如果沒有的話map是不會執(zhí)行的
    // subscribeNext就是定義了一個(gè)接收體
    [[[[RACSignal interval:2] take:1] map:^id(id _){
        // the value is from url request
        NSString *value = @"content fetched from web";
        [subject sendNext:value];
        return nil;
    }] subscribeNext:^(id _){}];
    return subject;
}
image

Signal and Subscriber

  • signal 和 subscriber 是RAC中最核心的涝涤,signal如果比喻成插座的話媚狰,subscriber 就是 插頭。插座負(fù)責(zé)去取電阔拳,插座負(fù)責(zé)使用崭孤。插頭可以無限串聯(lián)(chain)。當(dāng)插座signal 什么都不干的時(shí)候糊肠,也就是處于冷狀態(tài)辨宠,有了插頭插才會去獲取,這個(gè)時(shí)候就處于熱狀態(tài)货裹。

  • signal 獲取到數(shù)據(jù)后嗤形,會調(diào)用subscriber的sendNext,sendComplete,sendError方法來傳送數(shù)據(jù),如果沒有sendComplete和sendError弧圆,新的值就會通過sendNext一直傳輸赋兵。

    //使用KVO監(jiān)聽了property的變化,只要username變化搔预,block就會執(zhí)行霹期。NSURLCache的currentDiskUsage就不能被RACObserve。
    [RACObserve(self, username) subscribeNext: ^(NSString *newName){
        NSLog(@"newName:%@", newName);
    }];
    
  • signal 很靈活拯田,被修改(map)经伙,過濾(filter),疊加(combine)勿锅,串聯(lián)(chain)帕膜,這有助于應(yīng)對更加復(fù)雜的情況.

//把登錄按鈕enable和用戶名輸入框、密碼輸入框溢十、loggingIn垮刹、self.loggedIn 綁定。如果reduce 輸出NO张弛,則登錄按鈕不能點(diǎn)擊荒典,反之則可以點(diǎn)擊。返回的值必須是object對象吞鸭。
RAC(self.logInButton, enabled) = [RACSignal
        combineLatest:@[
            self.usernameTextField.rac_textSignal,
            self.passwordTextField.rac_textSignal,
            RACObserve(LoginManager.sharedManager, loggingIn),
            RACObserve(self, loggedIn)
        ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) {
            return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue);
        }];

冷信號(Cold)和熱信號(Hot)

  • createSignal 創(chuàng)建了信號但是沒有訂閱寺董,所以此時(shí)這個(gè)信號處于冷狀態(tài)。
  • 當(dāng)創(chuàng)建的信號被訂閱后刻剥,狀態(tài)才會變成熱狀態(tài).

Cocoa Categories
為了更加方便地使用RAC遮咖,RAC給Cocoa添加了很多category,與系 統(tǒng)集成地越緊密造虏,使用起來自然也就越方便

  • UIView Categories

    //點(diǎn)擊button后會發(fā)出信號signal御吞,通過rac_command處理
      @weakify(self)
        self.myButton.rac_command = [[RACCommand alloc] initWithEnabled:self.enable signalBlock:^RACSignal *(id input) {
            // Assume that we're logged in at first. We'll replace this signal later if not.
            RACSignal *authSignal = [RACSignal empty];
            //判斷條件是否通過
            if (self.enable) {
                //未通過后的處理
                    return nil;
                };
            return [authSignal then:^RACSignal *{
                @strongify(self);
                //通過后的處理
                return nil;
            }];
        }];
        [self.myButton.rac_command.errors subscribeNext:^(id x) {
            [x subscribeNext:^(NSError *error) {
                //失敗處理
            }];
        }];
    
    
  • 常用的數(shù)據(jù)結(jié)構(gòu)也添加了相應(yīng)的category麦箍。

    //NSArray為例
    NSArray *array = @[@1,@12,@3,@4];
        //有序的不可變集合,是運(yùn)行時(shí)計(jì)算的陶珠,所以對性能提升有一定的幫助
        RACSequence *sequece = [array rac_sequence];
        //轉(zhuǎn)換成NSArray
        NSArray *testArray =  [sequece array];
        [sequece any:^BOOL(id  _Nullable value) {
            //檢查sequece中的每一個(gè)元素是否符合要求
        }];
        [sequece all:^BOOL(id  _Nullable value) {
            //檢查是不是所有的元素都符合要求
        }];
    
  • 通知(NotificationCenter)
    默認(rèn)情況下使用 通知 的話需要使用Target-Action方式來處理Notifiction挟裂,這樣就需要從新定義一個(gè)方法,而且還要起名字(編程領(lǐng)域的兩大難題之一)防止重名揍诽。還需要在合適的時(shí)候移除observer诀蓉。

    //RAC 實(shí)現(xiàn) 不用擔(dān)心observer移除問題。
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"MyNotification" object:nil] subscribeNext:^(NSNotification *notification) {
        NSLog(@"Notification Received");
    }];
    
  • NSObject

    • 一個(gè)object的dealloc被觸發(fā)時(shí)暑脆,執(zhí)行的一段代碼.《NSObject+RACDeallocating.h》

      ```
      

      NSArray *array = @[@"foo"];
      [[array rac_willDeallocSignal] subscribeCompleted:^{
      NSLog(@"oops, i will be gone");
      }];
      array = nil;

    • 滿足一定條件時(shí)渠啤,自動觸發(fā)某個(gè)方法《NSObject+RACLifting.h》

      //當(dāng)signalA和signalB都至少sendNext過一次,接下來只要其中任意一個(gè)signal有了新的內(nèi)容饵筑,doA:withB這個(gè)方法就會自動被觸發(fā)。
      - (void)test
      {
          RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
              double delayInSeconds = 2.0;
              dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
              dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                  [subscriber sendNext:@"A"];
              });
              return nil;
          }];
          RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
              [subscriber sendNext:@"B"];
              [subscriber sendNext:@"Another B"];
              [subscriber sendCompleted];
              return nil;
          }];
          [self rac_liftSelector:@selector(doA:withB:) withSignals:signalA, signalB, nil];
      }
      - (void)doA:(NSString *)A withB:(NSString *)B
      {
          NSLog(@"A:%@ and B:%@", A, B);
          // A:A and B:Another B
      }
      
  • NSObject+RACSelectorSignal.h

    • rac_signalForSelector:某個(gè)事件響應(yīng)后同時(shí)做一個(gè)操作处坪。相當(dāng)于hook.
    • rac_signalForSelector:fromProtocol:selector實(shí)現(xiàn)了某個(gè)協(xié)議根资,所以可以用它來實(shí)現(xiàn)Delegate
      [[self rac_signalForSelector:@selector(test)]subscribeNext:^(RACTuple * _Nullable x) {
            //執(zhí)行test方法的時(shí)候,也把這里執(zhí)行了同窘。
        }];
        //這個(gè)方法主要是把 protocal 轉(zhuǎn)為一個(gè) Signal 便于使用玄帕。值得注意的是這個(gè)函數(shù)返回的是一個(gè) RACTuple。 這個(gè) RACTuple 包含了 Selector 方法里面所有的參數(shù)想邦。這樣需要用到的時(shí)候主要按照順序來獲取裤纹。RAC 來替代 Delegate .
        [[self rac_signalForSelector:@selector(test) fromProtocol:(@protocol(UITableViewDelegate))]mapReplace:@YES];
    

小結(jié):

  • 當(dāng)一個(gè)signalsubscriber 訂閱后,這個(gè)subscriber會在執(zhí)行到sendCompletesendError移除丧没。也可以手動移除[disposable dispose].當(dāng) subscriberdispose后鹰椒,所有相關(guān)subscriber相關(guān)的工作都會停止,資源也會釋放呕童。
  • Signal evente 是線性的漆际,不會出現(xiàn)并發(fā)的情況,除非顯示的指定 Scheduler,所以夺饲,-subscribeNext:error:completed: 里的block 不需要鎖定或者synchronized等操作奸汇,其他的events會依次排隊(duì),直到block處理完成往声。
  • Error有優(yōu)先權(quán)擂找,如果多個(gè)signal被同時(shí)監(jiān)聽,只要有一個(gè)signal SendError就會被傳送給subscriber,并導(dǎo)致signal全部終止執(zhí)行浩销,相當(dāng)于 Exception
  • 生成Signal時(shí)贯涎,最好指定Name, -setNameWithFormat:方便調(diào)試慢洋。
  • block代碼中不要阻塞柬采。

參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末欢唾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子粉捻,更是在濱河造成了極大的恐慌礁遣,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肩刃,死亡現(xiàn)場離奇詭異祟霍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盈包,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門沸呐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人呢燥,你說我怎么就攤上這事崭添。” “怎么了叛氨?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵呼渣,是天一觀的道長。 經(jīng)常有香客問我寞埠,道長屁置,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任仁连,我火速辦了婚禮蓝角,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饭冬。我一直安慰自己使鹅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布昌抠。 她就那樣靜靜地躺著并徘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扰魂。 梳的紋絲不亂的頭發(fā)上麦乞,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機(jī)與錄音劝评,去河邊找鬼姐直。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蒋畜,可吹牛的內(nèi)容都是我干的声畏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼插龄!你這毒婦竟也來了愿棋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤均牢,失蹤者是張志新(化名)和其女友劉穎糠雨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徘跪,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡甘邀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了垮庐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片松邪。...
    茶點(diǎn)故事閱讀 40,438評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖哨查,靈堂內(nèi)的尸體忽然破棺而出逗抑,到底是詐尸還是另有隱情,我是刑警寧澤寒亥,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布邮府,位于F島的核電站,受9級特大地震影響护盈,放射性物質(zhì)發(fā)生泄漏挟纱。R本人自食惡果不足惜羞酗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一腐宋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧檀轨,春花似錦胸竞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讹挎,卻和暖如春校赤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筒溃。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工马篮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人怜奖。 一個(gè)月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓浑测,卻偏偏與公主長得像,于是被迫代替她去往敵國和親歪玲。 傳聞我的和親對象是個(gè)殘疾皇子迁央,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評論 2 359

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