最全的 Swift 4 新特性解析

WWDC 2017 帶來了很多驚喜物遇。Swift 4 也伴隨著 Xcode 9 測試版來到了我們的面前乃沙,很多強大的新特性非常值得我們期待在正式項目中去使用它。因為 Swift 4 是開源的,如果你關注 swift-evolution 這個項目的話变姨,就應該已經提前了解到它的新特性了怒竿。本文參考了 WWDC 2017 以及各種資料睦番,從語法厚骗、字符串、標準庫、構建過程等方面,把 Swift 4 的這些新特性一一列舉出來做介紹和分析,讓他們毫無保留地展現(xiàn)在你眼前微驶。

一篇恒、語法改進

extension 中可以訪問 private 的屬性

考慮以下代碼:

struct Date: Equatable, Comparable {
    private let secondsSinceReferenceDate: Double
    static func ==(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
    static func <(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
}

上面代碼定義了一個 Date 結構體,并實現(xiàn) Equatable 和 Comparable 協(xié)議。為了讓代碼更清晰阻课,可讀性更好署驻,一般會把對協(xié)議的實現(xiàn)放在單獨的 extension 中宣吱,這也是一種非常符合 Swift 風格的寫法朴上,如下:

struct Date {
    private let secondsSinceReferenceDate: Double
}
extension Date: Equatable {
    static func ==(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
}
extension Date: Comparable {
    static func <(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
}

但是在 Swift 3 中卒煞,編譯就報錯了痪宰,因為 extension 中無法獲取到 secondsSinceReferenceDate 屬性,因為它是 private 的。于是在 Swift 3 中衣撬,必須把 private 改為 fileprivate乖订。

struct Date {
    fileprivate let secondsSinceReferenceDate: Double
}
...

但是如果用 fileprivate,屬性的作用域就會比我們需要的更大具练,可能會不小心造成屬性的濫用乍构。

在 Swift 4 中,private 的屬性的作用域擴大到了 extension 中扛点,并且被限定在了 struct 和 extension 內部哥遮,這樣就不需要再改成 fileprivate 了,這是最好的結果陵究。

類型和協(xié)議的組合類型

考慮以下代碼:

protocol Shakeable {
    func shake()
}

extension UIButton: Shakeable { /* ... */ }
extension UISlider: Shakeable { /* ... */ }

func shakeEm(controls: [???]) {
    for control in controls where control.state.isEnabled {
    }
    control.shake()
}

在 Swift 3 中眠饮,這里的 ??? 應該寫什么呢?如果寫 UIControl铜邮,那么 control.shake() 就會報錯仪召;如果寫 Shakeable,那么 control.state.isEnabled 就會報錯松蒜。其實我們也可以這樣寫:

func shakeEm(controls: [UIControl]) {
    for control in controls where control.isEnabled {
        if control is Shakeable {
            (control as! Shakeable).shake()
        }
    }
}

這樣寫雖然可以跑通了扔茅,但是很丑陋。

在 Swift 4 中秸苗,可以把類型和協(xié)議用 & 組合在一起作為一個類型使用咖摹,就可以像下面這樣寫了:

protocol Shakeable {
    func shake()
}

extension UIButton: Shakeable { /* ... */ }
extension UISlider: Shakeable { /* ... */ }

func shakeEm(controls: [UIControl & Shakeable]) {
    for control in controls where control.state.isEnabled {
        control.shake()
    }
}

把它聲明為了 UIControl & Shakeable 類型。OK难述,圓滿解決萤晴。

PS:
這個代碼例子是 WWDC 2017 的 PPT 中的,上面的代碼有點問題胁后,control.state.isEnabled 這句代碼中店读,state 是沒有 isEnabled 這個屬性的,改為 control.isEnabled 就可以了攀芯⊥投希看來蘋果的工程師做 PPT 有時候還是不太嚴謹。

另外侣诺,iOS SDK 中的 API 也用這個特性做了優(yōu)化殖演,例如:

// Objective-C API
@interface NSCandidateListTouchBarItem<CandidateType> : NSTouchBarItem
@property (nullable, weak) NSView <NSTextInputClient> *client;
@end

這個 API 的 Objective-C 版本是沒有問題的,可以知道 client 屬性既是一個 NSView年鸳,又符合 NSTextInputClient 協(xié)議趴久。然而它對應的 Swift 3 版本為:

class NSCandidateListTouchBarItem<CandidateType: AnyObject> : NSTouchBarItem {
    var client: NSView?
}

僅僅是一個 NSView 類型 /(ㄒoㄒ)/~~

在 Swift 4 中,這類 API 做了優(yōu)化搔确,改成了:

class NSCandidateListTouchBarItem<CandidateType: AnyObject> : NSTouchBarItem {
    var client: (NSView & NSTextInputClient)?
}

這樣類型的聲明就更加嚴謹了彼棍。

Associated Type 可以追加 Where 約束語句

在 Swift 4 中可以在 associatedtype 后面聲明的類型后追加 where 語句

associatedtype Element where <xxx>

看下面是 Swift 4 標準庫中 Sequence 中 Element 的聲明:

protocol Sequence {
    associatedtype Element where Self.Element == Self.Iterator.Element
    // ...
}

它限定了 Sequence 中 Element 這個類型必須和 Iterator.Element 的類型一致灭忠。

通過 where 語句可以對類型添加更多的約束,使其更嚴謹座硕,避免在使用這個類型時做多余的類型判斷弛作。

新的 Key Paths 語法

先來看看 Swift 3 中 Key Paths 的寫法:

@objcMembers class Kid: NSObject {
    dynamic var nickname: String = ""
    dynamic var age: Double = 0.0
    dynamic var friends: [Kid] = []
}

var ben = Kid(nickname: "Benji", age: 5.5)

let kidsNameKeyPath = #keyPath(Kid.nickname)

let name = ben.valueForKeyPath(kidsNameKeyPath)
ben.setValue("Ben", forKeyPath: kidsNameKeyPath)

Swift 4 中創(chuàng)建一個 KeyPath 用 \ 作為開頭:

\Kid.nickname

當編譯器可以推導出類型時,可以省略基礎類型部分:

\.nickname

上面的代碼在 Swift 4 中就可以這樣寫:

struct Kid {
    var nickname: String = ""
    var age: Double = 0.0
    var friends: [Kid] = []
}

var ben = Kid(nickname: "Benji", age: 8, friends: [])

let name = ben[keyPath: \Kid.nickname]
ben[keyPath: \Kid.nickname] = "BigBen"

相比 Swift 3华匾,Swift 4 的 Key Paths 具有以下優(yōu)勢:

  1. 類型可以定義為 class映琳、struct
  2. 定義類型時無需加上 @objcMembers、dynamic 等關鍵字
  3. 性能更好
  4. 類型安全和類型推斷蜘拉,例如 ben.valueForKeyPath(kidsNameKeyPath) 返回的類型是 Any萨西,ben[keyPath: \Kid.nickname] 直接返回 String 類型
  5. 可以在所有值類型上使用

下標支持泛型

有時候會寫一些數(shù)據(jù)容器,Swift 支持通過下標來讀寫容器中的數(shù)據(jù)诸尽,但是如果容器類中的數(shù)據(jù)類型定義為泛型原杂,以前的下標語法就只能返回 Any印颤,在取出值后需要用 as? 來轉換類型您机。Swift 4 定義下標也可以使用泛型了。

struct GenericDictionary<Key: Hashable, Value> {
    private var data: [Key: Value]
    
    init(data: [Key: Value]) {
        self.data = data
    }
    
    subscript<T>(key: Key) -> T? {
        return data[key] as? T
    }
}

let dictionary = GenericDictionary(data: ["Name": "Xiaoming"])

let name: String? = dictionary["Name"] // 不需要再寫 as? String

二年局、字符串

Unicode 字符串在計算 count 時的正確性改善

在 Unicode 中际看,有些字符是由幾個其它字符組成的,比如 é 這個字符矢否,它可以用 \u{E9} 來表示仲闽,也可以用 e 字符和上面一撇字符組合在一起表示 \u{65}\u{301}

考慮以下代碼:

var family = "??"
family += "\u{200D}??"
family += "\u{200D}??" 
family += "\u{200D}??"

print(family)
print(family.characters.count)

這個 family 是一個由多個字符組合成的字符僵朗,打印出來的結果為 ???????????赖欣。上面的代碼在 Swift 3 中打印的 count 數(shù)是 4,在 Swift 4 中打印出的 count 是 1验庙。

更快的字符處理速度

Swift 4 的字符串優(yōu)化了底層實現(xiàn)顶吮,對于英語、法語粪薛、德語悴了、西班牙語的處理速度提高了 3.5 倍。

對于簡體中文违寿、日語的處理速度提高了 2.5 倍湃交。

去掉 characters

Swift 3 中的 String 需要通過 characters 去調用的屬性方法,在 Swift 4 中可以通過 String 對象本身直接調用藤巢,例如:

let values = "one,two,three..."
var i = values.characters.startIndex

while let comma = values.characters[i...<values.characters.endIndex].index(of: ",") {
    if values.characters[i..<comma] == "two" {
        print("found it!")
    }
    i = values.characters.index(after: comma)
}

Swift 4 可以把上面代碼中的所有的 characters 都去掉搞莺,修改如下:

let values = "one,two,three..."
var i = values.startIndex

while let comma = values[i...<values.endIndex].index(of: ",") {
    if values[i..<comma] == "two" {
        print("found it!")
    }
    i = values.index(after: comma)
}

One-sided Slicing

Swift 4 新增了一個語法糖 ... 可以對字符串進行單側邊界取子串。

Swift 3:

let values = "abcdefg"
let startSlicingIndex = values.index(values.startIndex, offsetBy: 3)
let subvalues = values[startSlicingIndex..<values.endIndex]
// defg

Swift 4:

let values = "abcdefg"
let startSlicingIndex = values.index(values.startIndex, offsetBy: 3)
let subvalues = values[startSlicingIndex...] // One-sided Slicing
// defg

String 當做 Collection 來用

Swift 4 中 String 可以當做 Collection 來用掂咒,并不是因為 String 實現(xiàn)了 Collection 協(xié)議腮敌,而是 String 本身增加了很多 Collection 協(xié)議中的方法阱当,使得 String 在使用時看上去就是個 Collection。例如:

翻轉字符串:

let abc: String = "abc"
print(String(abc.reversed()))
// cba

遍歷字符:

let abc: String = "abc"
for c in abc {
    print(c)
}
/*
a
b
c
*/

Map糜工、Filter弊添、Reduce:

// map
let abc: String = "abc"
_ = abc.map {
    print($0.description)
}

// filter
let filtered = abc.filter { $0 == "b" }

// reduce
let result = abc.reduce("1") { (result, c) -> String in
    print(result)
    print(c)
    return result + String(c)
}
print(result)

Substring

在 Swift 中,String 的背后有個 Owner Object 來跟蹤和管理這個 String捌木,String 對象在內存中的存儲由內存其實地址油坝、字符數(shù)、指向 Owner Object 指針組成刨裆。Owner Object 指針指向 Owner Object 對象澈圈,Owner Object 對象持有 String Buffer。當對 String 做取子字符串操作時帆啃,子字符串的 Owner Object 指針會和原字符串指向同一個對象瞬女,因此子字符串的 Owner Object 會持有原 String 的 Buffer音瓷。當原字符串銷毀時伯铣,由于原字符串的 Buffer 被子字符串的 Owner Object 持有了女阀,原字符串 Buffer 并不會釋放塌衰,造成極大的內存浪費通殃。

在 Swift 4 中跛十,做取子串操作的結果是一個 Substring 類型豆巨,它無法直接賦值給需要 String 類型的地方蜻拨。必須用 String(<substring>) 包一層压怠,系統(tǒng)會通過復制創(chuàng)建出一個新的字符串對象眠冈,這樣原字符串在銷毀時,原字符串的 Buffer 就可以完全釋放了菌瘫。

let big = downloadHugeString()
let small = extractTinyString(from: big)

mainView.titleLabel.text = small // Swift 4 編譯報錯

mainView.titleLabel.text = String(small) // 編譯通過

多行字符串字面量

Swift 3 中寫很長的字符串只能寫在一行蜗顽。

func tellJoke(name: String, character: Character) {
    let punchline = name.filter { $0 != character }
    let n = name.count - punchline.count
    let joke = "Q: Why does \(name) have \(n) \(character)'s in their name?\nA: I don't know, why does \(name) have \(n) \(character)'s in their name?\nQ: Because otherwise they'd be called \(punchline)."
    print(joke)
}
tellJoke(name: "Edward Woodward", character: "d")

字符串中間有換行只能通過添加 \n 字符來代表換行。

Swift 4 可以把字符串寫在一對 """ 中雨让,這樣字符串就可以寫成多行雇盖。

func tellJoke(name: String, character: Character) {
    let punchline = name.filter { $0 != character }
    let n = name.count - punchline.count
    let joke = """
        Q: Why does \(name) have \(n) \(character)'s in their name?
        A: I don't know, why does \(name) have \(n) \(character)'s in their name?
        Q: Because otherwise they'd be called \(punchline).
        """
    print(joke)
}
tellJoke(name: "Edward Woodward", character: "d")

三、Swift 標準庫

Encoding and Decoding

當需要將一個對象持久化時宫患,需要把這個對象序列化刊懈,往常的做法是實現(xiàn) NSCoding 協(xié)議,寫過的人應該都知道實現(xiàn) NSCoding 協(xié)議的代碼寫起來很痛苦娃闲,尤其是當屬性非常多的時候虚汛。幾年前有一個工具能自動生成 Objective-C 的實現(xiàn) NSCoding 協(xié)議代碼,當時用著還不錯皇帮,但后來這個工具已經沒有人維護很久了卷哩,而且不支持 Swift。

Swift 4 中引入了 Codable 幫我們解決了這個問題属拾。

struct Language: Codable {
    var name: String
    var version: Int
}

我們想將這個 Language 對象的實例持久化将谊,只需要讓 Language 符合 Codable 協(xié)議即可冷溶,Language 中不用寫別的代碼。符合了 Codable 協(xié)議以后尊浓,可以選擇把對象 encode 成 JSON 或者 PropertyList逞频。

Encode 操作如下:

let swift = Language(name: "Swift", version: 4)
if let encoded = try? JSONEncoder().encode(swift) {
    // 把 encoded 保存起來
}

Decode 操作如下:

if let decoded = try? JSONDecoder().decode(Language.self, from: encoded) {
    print(decoded.name)
}

Sequence 改進

Swift 3:

protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    func makeIterator() -> Iterator
}

Swift 4:

protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
    func makeIterator() -> Iterator
}

由于 Swift 4 中的 associatedtype 支持追加 where 語句,所以 Sequence 做了這樣的改進栋齿。
Swift 4 中獲取 Sequence 的元素類型可以不用 Iterator.Element苗胀,而是直接取 Element。

SubSequence 也做了修改:

protocol Sequence {
    associatedtype SubSequence: Sequence 
        where SubSequence.SubSequence == SubSequence,
              SubSequence.Element == Element
}

通過 where 語句的限定瓦堵,保證了類型正確基协,避免在使用 Sequence 時做一些不必要的類型判斷。

Collection 也有一些類似的修改菇用。

Protocol-oriented integers

整數(shù)類型符合的協(xié)議有修改澜驮,新增了 FixedWidthInteger 等協(xié)議,具體的協(xié)議繼承關系如下:

                +-------------+   +-------------+
        +------>+   Numeric   |   | Comparable  |
        |       |   (+,-,*)   |   | (==,<,>,...)|
        |       +------------++   +---+---------+
        |                     ^       ^
+-------+------------+        |       |
|    SignedNumeric   |      +-+-------+-----------+
|     (unary -)      |      |    BinaryInteger    |
+------+-------------+      |(words,%,bitwise,...)|
       ^                    ++---+-----+----------+
       |         +-----------^   ^     ^---------------+
       |         |               |                     |
+------+---------++    +---------+---------------+  +--+----------------+
|  SignedInteger  |    |  FixedWidthInteger      |  |  UnsignedInteger  |
|                 |    |(endianness,overflow,...)|  |                   |
+---------------+-+    +-+--------------------+--+  +-+-----------------+
                ^        ^                    ^       ^
                |        |                    |       |
                |        |                    |       |
               ++--------+-+                +-+-------+-+
               |Int family |-+              |UInt family|-+
               +-----------+ |              +-----------+ |
                 +-----------+                +-----------+

Dictionary and Set enhancements

這里簡單列一下 Dictionary 和 Set 增強了哪些功能:

  1. 通過 Sequence 來初始化
  2. 可以包含重復的 Key
  3. Filter 的結果的類型和原類型一致
  4. Dictionary 的 mapValues 方法
  5. Dictionary 的默認值
  6. Dictionary 可以分組
  7. Dictionary 可以翻轉

NSNumber bridging and Numeric types

let n = NSNumber(value: 999)
let v = n as? UInt8 // Swift 4: nil, Swift 3: 231

在 Swift 4 中惋鸥,把一個值為 999 的 NSNumber 轉換為 UInt8 后杂穷,能正確的返回 nil,而在 Swift 3 中會不可預料的返回 231揩慕。

MutableCollection.swapAt(::)

MutableCollection 現(xiàn)在有了一個新方法 swapAt(::) 用來交換兩個位置的值亭畜,例如:

var mutableArray = [1, 2, 3, 4]
mutableArray.swapAt(1, 2)
print(mutableArray)
// 打印結果:[1, 3, 2, 4]

四扮休、構建過程改進

New Build System

Xcode 9 引入了 New Build System迎卤,可在 Xcode 9 的 File -> Project Settings... 中選擇開啟。

預編譯 Bridging Headers 文件

對于 Swift 和 Objective-C 混合的項目玷坠,Swift 調用 Objective-C 時蜗搔,需要建立一個 Bridging Headers 文件,然后把 Swift 要調用的 Objective-C 類的頭文件都寫在里面八堡,編譯器會讀取 Bridging Headers 中的頭文件樟凄,然后生成一個龐大的 Swift 文件,文件內容是這些頭文件內的 API 的 Swift 版本兄渺。然后編譯器會在編譯每一個 Swift 文件時缝龄,都要編譯一遍這個龐大的 Swift 文件的內容。

有了預編譯 Bridging Headers 以后挂谍,編譯器會在預編譯階段把 Bridging Headers 編譯一次叔壤,然后插入到每個 Swift 文件中,這樣就大大提高了編譯速度口叙。

蘋果宣稱 Xcode 9 和 Swift 4 對于 Swift 和 Objective-C 混合編譯的速度提高了 40%炼绘。

Indexing 可以在編譯的同時進行

用 Swift 開發(fā)項目時,近幾個版本的 Xcode 進行 Indexing 的速度慢的令人發(fā)指妄田。Xcode 9 和 Swift 4 在這方面做了優(yōu)化俺亮,可以在編譯的同時進行 Indexing驮捍,一般編譯結束后 Indexing 也會同時完成。

COW Existential Containers

Swift 中有個東西叫 Existential Containers脚曾,它用來保存未知類型的值东且,它的內部是一個 Inline value buffer,如果 Inline value buffer 中的值占用空間很大時本讥,這個值會被分配在堆上苇倡,然而在堆上分配內存是一個性能比較慢的操作。

Swift 4 中為了優(yōu)化性能引入了 COW Existential Containers囤踩,這里的 COW 就代表 "Copy-On-Write"旨椒,當存在多個相同的值時,他們會共用 buffer 上的空間堵漱,直到某個值被修改時综慎,這個被修改的值才會被拷貝一份并分配內存空間。

移除未調用的協(xié)議實現(xiàn)

struct Date {
    private let secondsSinceReferenceDate: Double
}

extension Date: Equatable {
    static func ==(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
}

extension Date: Comparable {
    static func <(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
}

看上面例子勤庐,Date 實現(xiàn)了 Equatable 和 Comparable 協(xié)議示惊。編譯時如果編譯器發(fā)現(xiàn)沒有任何地方調用了對 Date 進行大小比較的方法,編譯器會移除 Comparable 協(xié)議的實現(xiàn)愉镰,來達到減小包大小的目的米罚。

減少隱式 @objc 自動推斷

在項目中想把 Swift 寫的 API 暴露給 Objective-C 調用,需要增加 @objc丈探。在 Swift 3 中录择,編譯器會在很多地方為我們隱式的加上 @objc,例如當一個類繼承于 NSObject碗降,那么這個類的所有方法都會被隱式的加上 @objc隘竭。

class MyClass: NSObject {
    func print() { ... } // 包含隱式的 @objc
    func show() { ... } // 包含隱式的 @objc
}

這樣很多并不需要暴露給 Objective-C 也被加上了 @objc。大量 @objc 會導致二進制文件大小的增加讼渊。

在 Swift 4 中动看,隱式 @objc 自動推斷只會發(fā)生在很少的當必須要使用 @objc 的情況,比如:

  1. 復寫父類的 Objective-C 方法
  2. 符合一個 Objective-C 的協(xié)議

其它大多數(shù)地方必須手工顯示的加上 @objc爪幻。

減少了隱式 @objc 自動推斷后菱皆,Apple Music app 的包大小減少了 5.7%。

五挨稿、 Exclusive Access to Memory

在遍歷一個 Collection 的時候可以去修改每一個元素的值仇轻,但是在遍歷時如果去添加或刪除一個元素就可能會引起 Crash。

例如為 MutableCollection 擴展一個 modifyEach 方法來修改每個元素的值叶组,代碼如下:

extension MutableCollection {
    mutating func modifyEach(_ body: (inout Element) -> ()) {
        for index in self.indices {
            body(&self[index])
        }
    }
}

假如在調用 modifyEach 時去刪除元素:

var numbers = [1, 2, 3]
numbers.modifyEach { element in
    element *= 2
    numbers.removeAll()
}

就會在運行時 Crash拯田。Swift 4 中引入了 Exclusive Access to Memory,使得這個錯誤可以在編譯時被檢查出來甩十。

六船庇、 兼容性

Xcode 9 中同時集成了 Swift 3.2 和 Swift 4吭产。

  1. Swift 3.2 完全兼容 Swift 3.1,并會在過時的語法或函數(shù)上報告警告鸭轮。
  2. Swift 3.2 具有 Swift 4 的一些寫法臣淤,但是性能不如 Swift 4。
  3. Swift 3.2 和 Swift 4 可以混合編譯窃爷,可以指定一部分模塊用 Swift 3.2 編譯邑蒋,一部分用 Swift 4 編譯。
  4. 遷移到 Swift 4 后能獲得 Swift 4 所有的新特性按厘,并且性能比 Swift 3.2 好医吊。

總結:當 Xcode 正式版發(fā)布后,現(xiàn)有的 Swift 代碼可以直接升級到 Swift 3.2 而不用做任何改動逮京,后續(xù)可以再遷移到 Swift 4卿堂。或者直接遷移到 Swift 4 也可以懒棉,Swift 4 相比 Swift 3 的 API 變化還是不大的草描,很多第三方庫都可以直接用 Swift 4 編譯。Swift 1 到 2 和 Swift 2 到 3 的遷移的痛苦在 3 到 4 的遷移上已經大大改善了策严。

七穗慕、參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市妻导,隨后出現(xiàn)的幾起案子逛绵,更是在濱河造成了極大的恐慌,老刑警劉巖栗竖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暑脆,死亡現(xiàn)場離奇詭異渠啤,居然都是意外死亡狐肢,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門沥曹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來份名,“玉大人,你說我怎么就攤上這事妓美〗┫伲” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵壶栋,是天一觀的道長辰如。 經常有香客問我,道長贵试,這世上最難降的妖魔是什么琉兜? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任凯正,我火速辦了婚禮,結果婚禮上豌蟋,老公的妹妹穿的比我還像新娘廊散。我一直安慰自己,他們只是感情好梧疲,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布允睹。 她就那樣靜靜地躺著,像睡著了一般幌氮。 火紅的嫁衣襯著肌膚如雪缭受。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天该互,我揣著相機與錄音贯涎,去河邊找鬼。 笑死慢洋,一個胖子當著我的面吹牛塘雳,可吹牛的內容都是我干的。 我是一名探鬼主播普筹,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼败明,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了太防?” 一聲冷哼從身側響起妻顶,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜒车,沒想到半個月后讳嘱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡酿愧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年沥潭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嬉挡。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡钝鸽,死狀恐怖,靈堂內的尸體忽然破棺而出庞钢,到底是詐尸還是另有隱情拔恰,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布基括,位于F島的核電站颜懊,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜河爹,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一使鹅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昌抠,春花似錦患朱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侨艾,卻和暖如春执虹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唠梨。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工袋励, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人当叭。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓茬故,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚁鳖。 傳聞我的和親對象是個殘疾皇子磺芭,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內容