【RxSwift】RxSwift的理論知識

目錄
一、RxSwift是什么,為什么要使用RxSwift
二、RxSwift的核心角色
?1、Event
?2、Observable
?3、Observer要做的處理
?4、Observer
三、Observer監(jiān)聽Observable,以及監(jiān)聽行為的釋放
?1、Observer監(jiān)聽Observable
?2、監(jiān)聽行為的釋放
四、Subjects


一、RxSwift是什么,為什么要使用RxSwift


RxSwift是響應(yīng)式編程的一個開源框架,所謂響應(yīng)式編程(Reactive Programming,簡稱RP)就是一種編程范式——即怎么寫代碼的方法論。

1??如果項目里你用的是MVVM架構(gòu)的話,響應(yīng)式編程則提供了更加簡單優(yōu)雅的方式來做ViewModel和View的雙向綁定,從而使得你的MVVM更加如虎添翼;2??傳統(tǒng)方式中我們經(jīng)常使用代理、block、通知等方式來進行事件傳遞,它們各有各的寫法,而響應(yīng)式編程則可以讓事件傳遞的方式做到統(tǒng)一——鏈式調(diào)用,同時能降低代碼的耦合度提高代碼內(nèi)聚度(事件里通常會攜帶數(shù)據(jù),所以可以直接把事件看成是數(shù)據(jù)、把事件傳遞看成是數(shù)據(jù)傳遞),當然響應(yīng)式編程還有很多其它方面的用途你可以去挖掘,比如在網(wǎng)絡(luò)請求方面的應(yīng)用、在手勢方面的應(yīng)用、在多個異步任務(wù)處理方面的應(yīng)用等。

比較出名和成熟的響應(yīng)式編程框架有:

  • ReactiveCocoa,簡稱RAC,有OC和Swift版本
  • ReactiveX,簡稱Rx,有眾多編程語言的版本,如RxJava、RxKotlin、RxSwift、RxDart等,它們的API基本都是一樣的,只不過是基于不同語言實現(xiàn)的而已,但是沒有OC版本,不過如果真得要用OC開發(fā),我們也可以O(shè)C和Swift混編來調(diào)用RxSwift

Rx有這么多編程語言的版本,足以說明大家都比較認可它的那一套機制,社區(qū)肯定要比RAC活躍得多,因此如果要選擇一個響應(yīng)式編程框架,推薦Rx。

項目里要想使用RxSwift,得先安裝RxSwift和RxCocoa這兩個框架,這里只演示使用CocoaPods的安裝方式,像使用其它三方庫一樣直接在Podfile文件里依賴這兩個框架,執(zhí)行pod install即可。

pod 'RxSwift', '~> 5.0'
pod 'RxCocoa', '~> 5.0'

然后在想使用RxSwift的地方導(dǎo)入這兩個框架。

// RxSwift是Rx標準API的Swift版本實現(xiàn),不包含任何iOS相關(guān)的內(nèi)容
import RxSwift
// RxCocoa則是基于RxSwift給iOS的UI控件擴展了很多Rx特性
import RxCocoa


二、RxSwift的核心角色


iOS開發(fā)中的KVO、通知都是觀察者設(shè)計模式,在設(shè)計模式中它可是一種重中之重的設(shè)計模式。比如寶寶在睡覺,爸爸媽媽總不能一直在旁邊看著吧,那樣就太累了,他們該做啥事做啥事,只要聽到寶寶的哭聲,給寶寶喂奶就行了,這就是一個典型的觀察者設(shè)計模式。在這個例子里,寶寶是被觀察者,爸爸媽媽是觀察者,只要被觀察者發(fā)出了事件——哭聲,觀察者收到后就會做出相應(yīng)的處理——喂奶。據(jù)此我們可以得到觀察者設(shè)計模式的核心角色:

  • 被觀察者(也叫發(fā)布者)
  • 被觀察者要發(fā)出的事件
  • 觀察者(也叫訂閱者)
  • 觀察者要做的處理

RxSwift跟觀察者設(shè)計模式很像,核心角色也是上面這四個。

1、Event

Event就是這么一個泛型枚舉:

public enum Event<Element> {
    case next(Element)
    case error(Swift.Error)
    case completed
}

這個泛型枚舉一共有三個值,所以事件一共有三種類型,也就是說Observable只可能發(fā)出這三種類型的事件:

  • next事件:一個攜帶正常數(shù)據(jù)的正常事件,正常數(shù)據(jù)的數(shù)據(jù)類型就是這個泛型Element、它可以是任意類型、不過早在Observable那兒就指定好了,正常數(shù)據(jù)會被掛在事件的element屬性上
  • error事件:一個攜帶錯誤信息的錯誤事件,錯誤信息的數(shù)據(jù)類型為Error類型,錯誤信息會被掛在事件的error屬性上
// Error其實是一個協(xié)議,要想發(fā)出error事件,我們就得自定義Error
enum CustomError: Error {
    case error1
    case error2
    case error3
}
  • completed事件:一個什么數(shù)據(jù)都不攜帶的完成事件

Event就是事件,它就是Observable隨著時間的推移源源不斷發(fā)出的東西。事件的作用就是作為數(shù)據(jù)的載體來攜帶數(shù)據(jù),next事件就是正常數(shù)據(jù)的載體,error事件就是錯誤信息的載體,也就是說Observable要想發(fā)送一個正常數(shù)據(jù)就發(fā)出一個next事件,Observable要想發(fā)送一個錯誤信息就發(fā)出一個error事件,需要注意的是Observable一旦發(fā)出error事件就代表它因錯誤而終止了,以后再也不會發(fā)出事件。completed事件雖然不是數(shù)據(jù)的載體,但它也是一個不可或缺的事件,Observable一旦發(fā)出completed事件就代表它正常終止了,以后再也不會發(fā)出事件。

2、Observable

Observable就是這么一個泛型類:

// 注意:類型為ObservableType
public class Observable<Element> : ObservableType {
    ...
}

Observable就是被觀察者,它其實是一個事件序列(Event Sequence),所以我們通常又稱它為被觀察序列。Observable的作用就是隨著時間的推移源源不斷地發(fā)出事件,你想它發(fā)出的事件掛什么數(shù)據(jù)類型的數(shù)據(jù)就把它的泛型Element搞成什么數(shù)據(jù)類型就行了。

  • 創(chuàng)建Observable及Observable發(fā)出事件
// 1、怎么創(chuàng)建一個observable?
//
// 調(diào)用Observable的類方法create就可以創(chuàng)建一個observable,假設(shè)這個observable發(fā)出的事件掛的數(shù)據(jù)為Int類型
//
// create方法的入?yún)⑹且粋€閉包,這個閉包的入?yún)⑹且粋€observer——這個observer就是將來監(jiān)聽該observable的observer,這個閉包的返回值是一個disposable
// create方法的返回值是一個observable
let observable = Observable<Int>.create { observer in
    // 2、observable怎么發(fā)出事件?
    //
    // 這個閉包屬于observable,所以在這個環(huán)境里:
    // observable給observer發(fā)出next事件,換句話說就是給observer發(fā)送一個next消息(消息機制),即讓observer調(diào)用一下它的onNext方法
    // observable給observer發(fā)出completed事件或error事件,同理
    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)
    observer.onCompleted()
//    observer.onError(CustomError.error1)
    
    // 因為observable一旦發(fā)出completed事件或error事件就終止了,所以后面這三個事件是發(fā)不出去的
    observer.onNext(4)
    observer.onNext(5)
    observer.onNext(6)
    
    return Disposables.create()
}
  • 快捷創(chuàng)建Observable及Observable發(fā)出事件
// 單個事件Observable:該Observable只能發(fā)出一個next事件 + 一個completed事件
//
// 1、調(diào)用Observable的類方法just就可以快捷創(chuàng)建一個單個事件observable,可以省略泛型,直接傳你想發(fā)送的數(shù)據(jù)就行,會自動給你泛好
// 2、創(chuàng)建好、被監(jiān)聽后,該Observable就會自動發(fā)出事件
let justObservable = Observable.just(1)

// 等價于
let observable = Observable<Int>.create { observer in
    observer.onNext(1)
    observer.onCompleted()
    return Disposables.create()
}
// 多個事件Observable:該Observable能發(fā)出多個next事件 + 一個completed事件
//
// 1、調(diào)用Observable的類方法from或of就可以快捷創(chuàng)建一個多個事件observable,可以省略泛型,直接傳你想發(fā)送的數(shù)據(jù)就行,會自動給你泛好
// 2、創(chuàng)建好、被監(jiān)聽后,該Observable就會自動發(fā)出事件
let fromObservable = Observable.from([1, 2, 3]) // 通過數(shù)組來生成多個next事件
let ofObservable = Observable.of(1, 2, 3) // 通過可變參數(shù)來生成多個next事件

// 等價于
let observable = Observable<Int>.create { observer in
    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)
    observer.onCompleted()
    return Disposables.create()
}
// 重復(fù)N次Observable:給定一個重復(fù)次數(shù)N,該Observable就會重復(fù)發(fā)出同一個next事件N次 + 一個completed事件
let repeatElementObservable = Observable.repeatElement(1)
repeatElementObservable.take(5)
// 定時器Observable:完全就是一個定時器,必須泛整型。延遲多長時間、每隔多長時間、在哪個線程,該Observable會像個定時器一樣不斷發(fā)出累加的整數(shù)
//
// 如果想取消定時器,其實不用取消定時器Observable,你只需要把監(jiān)聽行為給釋放掉就可以了,這樣的話定時器Observable還是存在的,它并不會發(fā)出completed事件或error事件
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)

3、Observer要做的處理

這個沒什么好說的,通常就是一個閉包。

4、Observer

Observer有兩種類型:AnyObserver(隨便什么東西都能充當AnyObserver這種類型的觀察者)和Binder(一般都是一些UI控件的屬性在充當Binder這種類型的觀察者),但它們都是一個泛型結(jié)構(gòu)體:

// 注意:類型為ObserverType
public struct AnyObserver<Element> : ObserverType {
    ...
}

// 注意:類型為ObserverType
public struct Binder<Element>: ObserverType {
    ...
}

Observer就是觀察者。Observer的作用就是監(jiān)聽Observable(至于怎么監(jiān)聽,會在下一小節(jié)說),并在收到Observable發(fā)出的事件時做出相應(yīng)的處理,需要注意的是Observer想要監(jiān)聽的數(shù)據(jù)的數(shù)據(jù)類型就是泛型的這個Element,如果它跟Observable和Event那里的泛型Element不一樣,我們就得先通過map等函數(shù)把數(shù)據(jù)類型給搞一樣。

  • 創(chuàng)建一個AnyObserver及AnyObserver做相應(yīng)的處理
// 1、怎么創(chuàng)建一個anyObeserver?
//
// 調(diào)用AnyObserver的init方法就可以創(chuàng)建一個anyObserver,假設(shè)這個anyObserver想要監(jiān)聽的數(shù)據(jù)的數(shù)據(jù)類型為Int
//
// init方法的入?yún)⑹且粋€閉包,這個閉包的入?yún)⑹且粋€event——這個event就是將來被觀察的Observable所發(fā)出的事件,這個閉包的執(zhí)行體就是AnyObserver要做的處理
let anyObserver = AnyObserver<Int>.init { event in
    // 2、anyObserver怎么做出相應(yīng)的處理?
    // 在這個閉包的執(zhí)行體里做相應(yīng)的處理即可
    switch event {
    case .next:
        print("next:\(event.element)")
    case .error:
        print("error:\(event.error)")
    case .completed:
        print("completed")
    }
}
  • 創(chuàng)建一個Binder及Binder做相應(yīng)的處理
// 1、怎么創(chuàng)建一個Binder?
//
// 調(diào)用Binder的init方法就可以創(chuàng)建一個binder,假設(shè)這個binder想要監(jiān)聽的數(shù)據(jù)的數(shù)據(jù)類型為String(假設(shè)我們想監(jiān)聽字符串數(shù)據(jù),把監(jiān)聽到的字符串數(shù)據(jù)設(shè)置到一個label上顯示)
//
// init方法的第一個入?yún)⑹侵改阋驯O(jiān)聽到的數(shù)據(jù)設(shè)置給誰來使用,通常是一個UI控件
// init方法的第二個入?yún)⑹且粋€閉包,這個閉包的第一個入?yún)⒕褪乔懊娴哪莻€UI控件,第二個入?yún)⒕褪潜O(jiān)聽到的字符串數(shù)據(jù),這個閉包的執(zhí)行體就是binder要做的處理
let binder = Binder<String>.init(label) { label, element in
    // 2、binder怎么做出相應(yīng)的處理?
    // 在這個閉包的執(zhí)行體里做相應(yīng)的處理即可
    label.text = element
}


三、Observer監(jiān)聽Observable,以及監(jiān)聽行為的釋放


1、Observer監(jiān)聽Observable

現(xiàn)在我們已經(jīng)成功擁有了四大核心角色,被觀察者 + 被觀察者要發(fā)出的事件、觀察者 + 觀察者要做的處理,那這兩大陣營怎么聯(lián)系起來呢,也就是說觀察者怎么才能收到被觀察者發(fā)出的事件、進而觸發(fā)相應(yīng)的處理呢?很簡單,就是Observer監(jiān)聽Observable。

  • AnyObserver監(jiān)聽Observable
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let anyObserver = AnyObserver<Int>.init { event in
    switch event {
    case .next:
        print("next:\(event.element)")  // 會打印:0、1、2、3、...
    case .error:
        print("error:\(event.error)")
    case .completed:
        print("completed")
    }
}

// anyObserver監(jiān)聽timerObservable,就這么簡單
timerObservable.subscribe(anyObserver)
  • Binder監(jiān)聽Observable
// 界面上搞一個label
@IBOutlet weak var label: UILabel!

let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
let binder = Binder<String>.init(label) { label, element in
    label.text = element
}

// binder監(jiān)聽timerObservable
// 但是timerObservable發(fā)出的事件掛的數(shù)據(jù)是Int類型
// 而binder監(jiān)聽的確實String類型
// 所以得把timerObservable發(fā)出的事件掛的Int數(shù)據(jù)通過map函數(shù)轉(zhuǎn)換成String數(shù)據(jù)
// 就這么簡單
timerObservable
    .map { element in
        return "數(shù)字是:\(element)"
    }
    .subscribe(binder)

// Binder還有一個專門的bindTo方法用來監(jiān)聽Observable,不過跟subscribe方法是等價的
timerObservable
    .map { element in
        return "數(shù)字是:\(element)"
    }
    .bind(to: binder)
  • 當然除了AnyObserver和Binder這種標標準準的Observer可以監(jiān)聽Observable之外,我們還可以直接用一個閉包來監(jiān)聽Observable,這種情況下這個閉包其實也是一個廣義上的觀察者,而且這個觀察者是把原來標標準準的觀察者和觀察者要做的處理兩個角色融為一體了
let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)

// 方式1
timerObservable
    .subscribe { event in
        switch event {
        case .next:
            print("next:\(event.element)")  // 會打印:0、1、2、3、...
        case .error:
            print("error:\(event.error)")
        case .completed:
            print("completed")
        }
    }

// 方式2
timerObservable
    .subscribe(onNext: { element in
        print("next:\(element)")  // 會打印:0、1、2、3、...
    }, onError: { error in
        print("error:\(error)")
    }, onCompleted: {
        print("completed")
    })

因此將來我們看到subscribe方法或bindTo方法前面的東西肯定就是個Observable,后面的東西肯定就是個廣義的Observer——標標準準的Observer + 閉包。

2、監(jiān)聽行為的釋放

其實每當Observer監(jiān)聽Observable時就產(chǎn)生了一個監(jiān)聽行為——即subscribe方法或bindTo方法會返回一個Disposable類型的實例,一定要記得在適當?shù)臅r機釋放這個監(jiān)聽行為,以免內(nèi)存泄漏,注意當這個監(jiān)聽行為被釋放后,僅僅是切斷了兩大陣營之間的聯(lián)系,Observable和Observer這些對象本身是沒被銷毀的。釋放的方式有三種:

  • 立即釋放監(jiān)聽行為(實際開發(fā)中使用較少)
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
        let anyObserver = AnyObserver<Int>.init { event in
            switch event {
            case .next:
                print("next:\(event.element)")
            case .error:
                print("error:\(event.error)")
            case .completed:
                print("completed")
            }
        }

        let disposable = timerObservable.subscribe(anyObserver)
        // 立即釋放監(jiān)聽行為——即接收完釋放之前的一波數(shù)據(jù)后立即釋放,類似于release
        disposable.dispose()
    }
}
  • 自動釋放監(jiān)聽行為(實際開發(fā)中使用較多)
class ViewController: UIViewController {
    // 類似于autoreleasepool
    //
    // 它會把所有的監(jiān)聽行為都放進去,等到它即將銷毀時再對它里面所有的監(jiān)聽行為都調(diào)用一次dispose方法
    // 現(xiàn)在bag屬性的生命周期是跟當前viewController一樣的
    let bag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
        let anyObserver = AnyObserver<Int>.init { event in
            switch event {
            case .next:
                print("next:\(event.element)")
            case .error:
                print("error:\(event.error)")
            case .completed:
                print("completed")
            }
        }
        
        timerObservable.subscribe(anyObserver).disposed(by: bag)
    }
}
  • 手動釋放監(jiān)聽行為
class ViewController: UIViewController {
    // 定義一個屬性
    var disposable: Disposable?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let timerObservable = Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance)
        let anyObserver = AnyObserver<Int>.init { event in
            switch event {
            case .next:
                print("next:\(event.element)")
            case .error:
                print("error:\(event.error)")
            case .completed:
                print("completed")
            }
        }
        
        // 把監(jiān)聽行為記錄下來
        disposable = timerObservable.subscribe(anyObserver)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // 在合適的時機手動釋放監(jiān)聽行為
        disposable?.dispose()
    }
}


四、Subjects


Subjects同時充當了Observable和Observer的角色,也就是說它既是一個被觀察者、也是一個觀察者,它既能發(fā)出事件、也能做相應(yīng)的處理。常用的Subjects有四種:

  • PublishSubject
class ViewController: UIViewController {
    let bag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let publishSubject = PublishSubject<Int>.init()
        
        // 這里publishSubject在充當Observer的角色,幫Observable發(fā)出事件
        // 還記得之前創(chuàng)建Observable時,Observable是怎么發(fā)出事件的嗎?就是給Observer發(fā)送onNext消息發(fā)出的,onNext本來就是Observer的方法,所以這里就體現(xiàn)了publishSubject在充當Observer的角色
        publishSubject.onNext(1)
        publishSubject.onNext(2)
        publishSubject.onNext(3)
        
        // 這里publishSubject在充當Observable的角色,只會向觀察者發(fā)送觀察者監(jiān)聽它之后的事件,不會向觀察者發(fā)送觀察者監(jiān)聽它之前的事件
        publishSubject.subscribe { event in
            print(event) // 4、5、6
        }.disposed(by: bag)
        
        
        publishSubject.onNext(4)
        publishSubject.onNext(5)
        publishSubject.onNext(6)
    }
}
  • BehaviorSubject
class ViewController: UIViewController {
    let bag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let behaviorSubject = BehaviorSubject<Int>(value: 1)

        // 這里behaviorSubject在充當Observer的角色,幫Observable發(fā)出事件
        behaviorSubject.onNext(2)
        behaviorSubject.onNext(3)

        // 這里behaviorSubject在充當Observable的角色,會向觀察者發(fā)送觀察者監(jiān)聽它之前的最后一個事件 + 觀察者監(jiān)聽它之后的事件
        behaviorSubject.subscribe { event in
            print(event) // 3、4、5、6
        }.disposed(by: bag)

        behaviorSubject.onNext(4)
        behaviorSubject.onNext(5)
        behaviorSubject.onNext(6)
    }
}
  • ReplaySubject
class ViewController: UIViewController {
    let bag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let replaySubject = ReplaySubject<Int>.create(bufferSize: 2) // 假設(shè)要緩存兩個事件
        
        // 這里replaySubject在充當Observer的角色,幫Observable發(fā)出事件
        replaySubject.onNext(1)
        replaySubject.onNext(2)
        replaySubject.onNext(3)
        
        // 這里replaySubject在充當Observable的角色,會向觀察者發(fā)送觀察者監(jiān)聽它之前緩存的N個事件 + 觀察者監(jiān)聽它之后的事件
        replaySubject.subscribe { event in
            print(event) // 2、3、4、5、6。緩存的是最后兩個事件,因為是序列,所以會按順序把事件發(fā)出來
        }.disposed(by: bag)
        
        replaySubject.onNext(4)
        replaySubject.onNext(5)
        replaySubject.onNext(6)
    }
}
  • BehaviorRelay(Variable已經(jīng)被廢棄了,用BehaviorRelay代替,它倆其實都是對BehaviorSubject的封裝,功能一樣)
class ViewController: UIViewController {
    let bag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let behaviorRelay = BehaviorRelay<Int>.init(value: 1)
        
        // 這里behaviorRelay在充當Observer的角色,幫Observable發(fā)出事件
        behaviorRelay.accept(2)
        behaviorRelay.accept(3)
        
        // 這里behaviorRelay在充當Observable的角色,會向觀察者發(fā)送觀察者監(jiān)聽它之前的最后一個事件 + 觀察者監(jiān)聽它之后的事件
        behaviorRelay.subscribe { event in
            print(event) // 3、4、5、6
        }.disposed(by: bag)
        
        behaviorRelay.accept(4)
        behaviorRelay.accept(5)
        behaviorRelay.accept(6)
    }
}

參考
1、RxSwift中文文檔
2、RxSwift大全

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

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