Swift 編碼風格指南

本文轉自:Swift 編碼風格指南 | www.samirchen.com

背景

本文主要是對以下幾個編碼規(guī)范的整理:

對其中少數(shù)規(guī)范,我根據(jù)自己的習慣做了修改迹淌。

這里有些關于編碼風格 Apple 官方文檔锰扶,如果有些東西沒有提及田绑,可以在以下文檔來查找更多細節(jié):

命名

使用駝峰命名法為 促绵、方法變量 等取一個描述性強的命名迂曲。禀忆、結構體枚舉狸页、協(xié)議 這些類型名應該首字母大寫锨能,而 方法變量 則應該首字母小寫芍耘。

推薦:

private let maximumWidgetCount = 100

class WidgetContainer {
    var widgetButton: UIButton
    let widgetHeightPercentage = 0.85
}

不推薦:

let MAX_WIDGET_COUNT = 100

class app_widgetContainer {
    var wBut: UIButton
    let wHeightPct = 0.85
}

一般情況下址遇,應該避免使用縮略詞。遵循 API Design Guidelines 的規(guī)范斋竞,當你使用常見的縮略詞時倔约,應該保持它們的大小寫一致性,要么所有字母都大寫坝初,要么所有字母都小寫浸剩。比如:

推薦:

let urlString: URLString
let userID: UserID

不推薦:

let uRLString: UrlString
let userId: UserId

對于函數(shù)和構造器,除非上下文已經很清晰鳄袍,最好為所有參數(shù)添加局部參數(shù)名绢要。如果可以的話,最好也添加外部參數(shù)名來讓函數(shù)調用語句更易讀拗小。

func dateFromString(dateString: String) -> NSDate
func convertPointAt(column column: Int, row: Int) -> CGPoint
func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction!

// would be called like this:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(afterDelay: 1.0, perform: someOtherAction)

對于類中的方法重罪,請遵循蘋果慣例,將方法名作為第一個參數(shù)的外部名:

class Counter {
    func combineWith(otherCounter: Counter, options: Dictionary?) { ... }
    func incrementBy(amount: Int) { ... }
}

協(xié)議

遵循蘋果的 API 設計規(guī)范,當協(xié)議是用來「描述一個東西是什么」時剿配,協(xié)議名應該是一個名詞搅幅,比如:CollectionWidgetFactory呼胚。當協(xié)議是用來「描述一種能力」時盏筐,協(xié)議名應該以 -ing-able-ible 結尾砸讳,比如:Equatable琢融、Resizing

枚舉

遵循蘋果的 API 設計規(guī)范對 Swift 3 的要求簿寂,使用首字母小寫的駝峰命名法來給枚舉值命名漾抬。

enum Shape {
    case rectangle
    case square
    case rightTriangle
    case equilateralTriangle
}

文字描述

在所有提及到函數(shù)的文字中(包括教程、書常遂、評論)纳令,請從調用者的視角進行考慮,將所有的必要參數(shù)名都包含進來克胳,比如:

Call convertPointAt(column:row:) from your own init implementation.

If you call dateFromString(_:) make sure that you provide a string with the format "yyyy-MM-dd".

If you call timedAction(afterDelay:perform:) from viewDidLoad() remember to provide an adjusted delay value and an action to perform.

You shouldn't call the data source method tableView(_:cellForRowAtIndexPath:) directly.

類名前綴

Swift 的類型會被自動包含到它所在模塊的命名空間中平绩,所以沒有必要再給 Swift 的類型添加類似 RW 這樣的前綴了。如果兩個不同模塊的存在相同的名字漠另,你可以通過在它們前面添加模塊名來避免沖突捏雌。當然,你應該只在必要的時候才添加模塊名前綴笆搓。

import SomeModule

let myClass = MyModule.UsefulClass()

選擇器

不要再用字符串來指定選擇器性湿,而應該使用新的語法方式,更安全满败。通常肤频,你應該使用上下文來縮短選擇器表達式。

推薦:

let sel = #selector(viewDidLoad)

不推薦:

let sel = #selector(ViewController.viewDidLoad)

泛型

泛型名應該有較好的閱讀性算墨,用首字母大寫的駝峰式命名宵荒。當一個類型沒有有意義的關系和角色,使用傳統(tǒng)的 T净嘀、U报咳、V 來替代。

推薦:

struct Stack<Element> { ... }
func writeTo<Target: OutputStream>(inout target: Target)
func max<T: Comparable>(x: T, _ y: T) -> T

不推薦:

struct Stack<T> { ... }
func writeTo<target: OutputStream>(inout t: target)
func max<Thing: Comparable>(x: Thing, _ y: Thing) -> Thing

語言

使用美式英語面粮,這樣更契合蘋果的 API少孝。

推薦:

let color = "red"

不推薦:

let colour = "red"

代碼結構

使用 // MARK: - 根據(jù)「代碼功能類別」继低、「protocol/delegate 方法實現(xiàn)」等依據(jù)對代碼進行分塊組織熬苍。代碼的組織順序從整體上盡量遵循我們的認知順序。

協(xié)議實現(xiàn)

其中,當你為一個類實現(xiàn)某些協(xié)議時柴底,推薦添加一個獨立的 extension 來實現(xiàn)具體的協(xié)議方法婿脸,這樣可以讓協(xié)議相關的代碼聚合在一起,從而保持代碼結構的清晰性柄驻,比如:

推薦:

class MyViewcontroller: UIViewController {
    // class stuff here
}

// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
    // table view data source methods
}

// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
    // scroll view delegate methods
}

不推薦:

class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
    // all methods
}

由于編譯器不允許在派生類重復聲明對協(xié)議的實現(xiàn)狐树,所以并不要求總是復制基類的 extension 組。尤其當這個派生類是一個終端類鸿脓,只有少量的方法需要重載時抑钟。何時保留 extension 組,這個應該由作者自己決定野哭。

對于 UIKit 的 ViewControllers在塔,可以考慮將 Lifecycle、Custom Accessors拨黔、IBAction 放在獨立的 extension 中實現(xiàn)蛔溃。

無用代碼

無用的代碼,包括 Xcode 代碼模板提供的默認代碼篱蝇,以及占位的評論贺待,都應該被刪掉。除非你是在寫教程需要讀者來閱讀你注釋的代碼零截。

不推薦:

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return Database.contacts.count
}

推薦:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return Database.contacts.count
}

最小引用

只 import 你需要的模塊麸塞。比如,如果引用 Foundation 以及足夠涧衙,就不要再引用 UIKit 了喘垂。

空白

  • 使用 Tab 而非空格。

  • 方法的大括號以及其他的大括號(if/else/switch/while 等)總是與關聯(lián)的程序語句在同一行打開绍撞,而在新起的一行結束正勒。

推薦:

if user.isHappy {
    // Do something
} else {
    // Do something else
}

不推薦:

if user.isHappy
{
    // Do something
}
else {
    // Do something else
}
  • 方法之間應該保留一行空格來使得代碼結構組織更清晰。在方法中傻铣,可以用空行來隔開功能塊章贞,但是當一個方法中存在太多功能塊時,那就意味著你可能需要重構這個大方法為多個小方法了非洲。

  • 冒號的左邊總是不空格鸭限,右邊空 1 格。除了在三元運算符 ? : 和空字典 [:] 中两踏。

推薦:

class TestDatabase: Database {
    var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
}

不推薦:

class TestDatabase : Database {
    var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
}

注釋

只在需要的時候添加注釋來解釋一段代碼的意義败京,注釋要么保持與對應的代碼一起更新,要不然就刪掉梦染。

避免使用在代碼中使用塊注釋赡麦,代碼應該是自解釋的朴皆。除非你的注釋是用來生成文檔的。

類和結構體

使用哪個

結構體是值類型泛粹,使用結構體來表示那些沒有區(qū)別性的事物遂铡。一個包含 [a, b, c] 元素的數(shù)組和另一個包含 [a, b, c] 元素的數(shù)組是完全可替換的,你用第一個數(shù)組和用第二個數(shù)組沒有任何區(qū)別晶姊,因為它們代表著同樣的東西扒接。所以數(shù)組是結構體。

類是引用類型们衙,使用類來表示那些有區(qū)別性的事物钾怔。你用類來表示「人」這個概念,是因為兩個「人」的實例是兩個不一樣的事情蒙挑。兩個「人」的實例就算擁有相同的姓名蒂教、生日,也不代表他們是一樣的脆荷。但是「人」的生日數(shù)據(jù)應該用結構體表示凝垛,因為一個 1950-03-03 和另一個 1950-03-03 是一回事,日期這個概念沒有區(qū)別性蜓谋。

有時候梦皮,一些概念本應是用結構體,但是由于歷史原因被實現(xiàn)為類了桃焕,比如 NSDate剑肯、NSSet。

類定義示例

以下是一個設計較好的類定義示例:

class Circle: Shape {
    var x: Int, y: Int
    var radius: Double
    var diameter: Double {
        get {
            return radius * 2
        }
        set {
            radius = newValue / 2
        }
    }

    init(x: Int, y: Int, radius: Double) {
        self.x = x
        self.y = y
        self.radius = radius
    }

    convenience init(x: Int, y: Int, diameter: Double) {
        self.init(x: x, y: y, radius: diameter / 2)
    }

    func describe() -> String {
        return "I am a circle at \(centerString()) with an area of \(computeArea())"
    }

    override func computeArea() -> Double {
        return M_PI * radius * radius
    }

    private func centerString() -> String {
        return "(\(x),\(y))"
    }
}

使用 Self

為了簡潔观堂,能不用 self 的地方就不用让网,因為 Swift 不需要用它來訪問屬性或調用方法。

Use self when required to differentiate between property names and arguments in initializers, and when referencing properties in closure expressions (as required by the compiler):

在下面情況中师痕,你需要使用 self

  • 在構造器中溃睹,為了區(qū)別傳入的參數(shù)和屬性。
  • 在閉包中訪問屬性胰坟,編譯器要求用 self因篇。
class BoardLocation {
    let row: Int, column: Int

    init(row: Int, column: Int) {
        self.row = row
        self.column = column

        let closure = {
            print(self.row)
        }
    }
}

計算屬性

為了簡潔,如果計算屬性是只讀的笔横,那么就省略 get竞滓。只有當同時寫了 set 語句時,才寫 get 語句吹缔。

推薦:

var diameter: Double {
    return radius * 2
}

不推薦:

var diameter: Double {
    get {
        return radius * 2
    }
}

Final

如果類不會被繼承商佑,那么將它設為 final 的。比如:

// Turn any generic type into a reference type using this Box class.
final class Box<T> {
    let value: T 
    init(_ value: T) {
        self.value = value
    }
}

函數(shù)聲明

對于較短的函數(shù)聲明厢塘,包括括號茶没,在一行完成肌幽。

func reticulateSplines(spline: [Double]) -> Bool {
    // reticulate code goes here
}

對于較長的函數(shù)聲明,在合適的地方換行礁叔,并在新起的一行加縮進牍颈。

func reticulateSplines(spline: [Double], adjustmentFactor: Double,
    translateConstant: Int, comment: String) -> Bool {
    // reticulate code goes here
}

閉包表達式

如果參數(shù)列表只有最后一個參數(shù)是閉包類型迄薄,則盡可能使用尾閉包語法琅关。在所有情況下給閉包參數(shù)一個描述性強的命名。

推薦:

UIView.animateWithDuration(1.0) {
    self.myView.alpha = 0
}

UIView.animateWithDuration(1.0,
    animations: {
        self.myView.alpha = 0
    },
    completion: { finished in
        self.myView.removeFromSuperview()
    }
)

不推薦:

UIView.animateWithDuration(1.0, animations: {
    self.myView.alpha = 0
})

UIView.animateWithDuration(1.0,
    animations: {
        self.myView.alpha = 0
    }) { f in
        self.myView.removeFromSuperview()
}

對于上下文清晰的單表達式閉包讥蔽,使用隱式的返回值:

attendeeList.sort { a, b in
    a > b
}

在鏈式方法調用中使用尾閉包語法時涣易,需要確保上下文清晰可讀。對于是否空行以及是否使用匿名參數(shù)等冶伞,則留給作者自行決定新症。例如:

let value = numbers.map { $0 * 2 }.filter { $0 % 3 == 0 }.indexOf(90)

let value = numbers
    .map {$0 * 2}
    .filter {$0 > 50}
    .map {$0 + 10}

類型

如果可以的話,總是優(yōu)先使用 Swift 提供的原生類型响禽。Swift 提供了對 Objective-C 的橋接徒爹,所以你可以使用所有需要的方法。

推薦:

let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String

不推薦:

let width: NSNumber = 120.0 // NSNumber
let widthString: NSString = width.stringValue // NSString

在 Sprite Kit 代碼中芋类,使用 CGFloat 來避免過多的轉換從而使代碼更簡練隆嗅。

常量

let 關鍵字來定義常量,使用 var 關鍵字來定義變量侯繁。如果變量不需要被修改胖喳,則應該總是選擇使用 let

一個建議是:總是使用 let 除非編譯器報警告訴你需要使用 var贮竟。

使用類型而非實例屬性來定義常量丽焊。最好也別用全局常量,這樣能更好區(qū)分常量和實例屬性咕别。如下:

推薦:

enum Math {
    static let e = 2.718281828459045235360287
    static let pi = 3.141592653589793238462643
}

radius * Math.pi * 2 // circumference

使用 case-less 枚舉的優(yōu)勢在于它不會被意外初始化技健,而僅僅作為一個 namespace 來用。

不推薦:

let e = 2.718281828459045235360287 // pollutes global namespace
let pi = 3.141592653589793238462643

radius * pi * 2 // is pi instance data or a global constant?

靜態(tài)方法和靜態(tài)類型屬性

靜態(tài)方法和靜態(tài)類型屬性與全局方法和全局變量類似惰拱,應該盡量少用凫乖。

Optional

當一個變量或函數(shù)返回值可以為 nil 時,用 ? 將其聲明為 Optional 的弓颈。

對于在使用前一定會被初始化的實例變量帽芽,用 ! 將其聲明為隱式解包類型(Implicitly Unwrapped Types)。

在訪問一個 Optional 值時翔冀,如果該值只被訪問一次导街,或者之后需要連續(xù)訪問多個 Optional 值,請使用鏈式 Optional 語法:

self.textContainer?.textLabel?.setNeedsDisplay()

對于需要將 Optional 值解開一次纤子,多處使用的情況搬瑰,使用 Optional 綁定更為方便:

if let textContainer = self.textContainer {
    // do many things with textContainer
}

不要使用類似 optionalString款票、maybeView 這種名字來命名 Optional 的變量或屬性,因為這層意思以及明顯的體現(xiàn)在他們的類型聲明上了泽论。

對于 Optional 綁定艾少,推薦直接用同樣的名字,不要用 unwrappedView翼悴、actualLabel 這種命名缚够。

推薦:

var subview: UIView?
var volume: Double?

// later on...
if let subview = subview, volume = volume {
    // do something with unwrapped subview and volume
}

不推薦:

var optionalSubview: UIView?
var volume: Double?

if let unwrappedSubview = optionalSubview {
  if let realVolume = volume {
    // do something with unwrappedSubview and realVolume
  }
}

結構體構造器

使用 Swift 原生的結構體構造器。

推薦:

let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)

不推薦:

let bounds = CGRectMake(40, 20, 120, 80)
let centerPoint = CGPointMake(96, 42)

推薦像 CGRect.infinite鹦赎、CGRect.null 這樣使用帶命名空間約束的結構體常量谍椅,不推薦像 CGRectInfiniteCGRectNull 這樣使用全局的結構體常量古话。對于已經存在的結構體類型變量雏吭,你可以使用類似 .zero 這樣的縮寫。

懶加載

使用懶加載機制來在對象的生命周期中實現(xiàn)更細粒度的內存和邏輯控制陪踩。尤其是 UIViewController杖们,在加載其 views 時,盡量采用懶加載方式肩狂≌辏可以使用 { }() 這種閉包的方式或者私有工廠的方式來實現(xiàn)懶加載。比如:

lazy var locationManager: CLLocationManager = self.makeLocationManager()

private func makeLocationManager() -> CLLocationManager {
  let manager = CLLocationManager()
  manager.desiredAccuracy = kCLLocationAccuracyBest
  manager.delegate = self
  manager.requestAlwaysAuthorization()
  return manager
}

注意:

  • 這里不需要 [unowned self]婚温,因為這里沒有引起循環(huán)引用描焰。
  • CLLocationManager 有一個副作用,會喚起向用戶申請權限的 UI 界面栅螟,所以在這里使用懶加載機制可以達到更細粒度的內存和邏輯控制荆秦。

類型推導

為了代碼緊湊,推薦盡量使用 Swift 的類型推導力图。不過步绸,對于 CGFloatInt16 這種吃媒,推薦盡量指定明確的類型瓤介。

推薦:

let message = "Click the button"
let currentBounds = computeViewBounds()
var names = ["Mic", "Sam", "Christine"]
let maximumWidth: CGFloat = 106.5

不推薦:

let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
let names = [String]()

注意: 遵循這條規(guī)范意味著選用一個描述性強的命名,比之前更重要了赘那。

類型標注

對于空的數(shù)組和字典刑桑,使用類型標注。

推薦:

var names: [String] = []
var lookup: [String: Int] = [:]

不推薦:

var names = [String]()
var lookup = [String: Int]()

語法糖

推薦使用簡短的聲明募舟。

推薦:

var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?

不推薦:

var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>

函數(shù)和方法

自由函數(shù)不屬于任何一個類或類型祠斧,應該盡量少用」敖福可以的話琢锋,盡量使用方法而非自由函數(shù)辕漂。這樣可讀性更好,也更易查找吴超。

最適合使用自由函數(shù)的場景是這個函數(shù)功能與任何特定的類或類型都沒有關聯(lián)關系钉嘹。

推薦:

let sorted = items.mergeSort() // easily discoverable
rocket.launch() // clearly acts on the model

不推薦:

let sorted = mergeSort(items) // hard to discover
launch(&rocket)

自由函數(shù)示例

let tuples = zip(a, b)  // feels natural as a free function (symmetry)
let value = max(x,y,z)  // another free function that feels natural

內存管理

在編碼中應該避免循環(huán)引用。對于會產生循環(huán)應用的地方鲸阻,使用 weakunowned 來解決跋涣。此外,還可以使用類型(struct赘娄、enum)來避免循環(huán)引用仆潮。

延伸對象生命周期

可以通過 [weak self]宏蛉、guard let strongSelf = self else { return } 來延伸對象的生命周期遣臼。

相對于 [unowned self],這里更推薦使用 [weak self]拾并。[unowned self] 在其作用的對象被釋放后揍堰,會造成野指針,而 [weak self] 則會將對應的引用置為 nil嗅义。

相對于 Optional 拆包屏歹,更推薦明確的延長生命周期。

推薦:

resource.request().onComplete { [weak self] response in
    guard let strongSelf = self else { return }
    let model = strongSelf.updateModel(response)
    strongSelf.updateUI(model)
}

不推薦:

// might crash if self is released before response returns
resource.request().onComplete { [unowned self] response in
    let model = self.updateModel(response)
    self.updateUI(model)
}

不推薦:

// deallocate could happen between updating the model and updating UI
resource.request().onComplete { [weak self] response in
    let model = self?.updateModel(response)
    self?.updateUI(model)
}

訪問控制

開發(fā)的訪問級別不需要把 public 寫出來之碗,但對于 private蝙眶,則最好寫出。

除了 static褪那、@IBAction幽纷、@IBOutlet,一般情況下博敬,總是把訪問控制修飾符 private 放在屬性修飾符的第一位友浸。

推薦:

class TimeMachine {  
    private dynamic lazy var fluxCapacitor = FluxCapacitor()
}

不推薦:

class TimeMachine {  
    lazy dynamic private var fluxCapacitor = FluxCapacitor()
}

控制流

相對于 while-condition-increment,更推薦使用 for-in偏窝。

推薦:

for _ in 0..<3 {
    print("Hello three times")
}

for (index, person) in attendeeList.enumerate() {
    print("\(person) is at position #\(index)")
}

for index in 0.stride(to: items.count, by: 2) {
    print(index)
}

for index in (0...3).reverse() {
    print(index)
}

不推薦:

var i = 0
while i < 3 {
    print("Hello three times")
    i += 1
}


var i = 0
while i < attendeeList.count {
    let person = attendeeList[i]
    print("\(person) is at position #\(i)")
    i += 1
}

黃金路徑

盡早 return 或 break收恢。當使用條件語句編寫邏輯時,左手的代碼應該是 「golden」 或 「happy」 路徑祭往。也就是說伦意,不要嵌套多個 if 語句,即使寫多個 return 語句也是 OK 的硼补。guard 就是用來做這事的驮肉。

推薦:

func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {

    guard let context = context else { throw FFTError.noContext }
    guard let inputData = inputData else { throw FFTError.noInputData }

    // use context and input to compute the frequencies

    return frequencies
}

不推薦:

func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {

    if let context = context {
        if let inputData = inputData {
            // use context and input to compute the frequencies

            return frequencies
        }
        else {
            throw FFTError.noInputData
        }
    }
    else {
        throw FFTError.noContext
    }
}

當多個 Optional 使用 guardif let 拆包,推薦最小化嵌套括勺。比如:

推薦:

guard let number1 = number1, number2 = number2, number3 = number3 else { fatalError("impossible") }
// do something with numbers

不推薦:

if let number1 = number1 {
    if let number2 = number2 {
        if let number3 = number3 {
            // do something with numbers
        }
        else {
            fatalError("impossible")
        }
    }
    else {
        fatalError("impossible")
    }
}
else {
    fatalError("impossible")
}

失敗的 Guard

guard 語句一般都需要以某種方式退出執(zhí)行缆八。一般來說使用 return曲掰、throwbreak奈辰、continue栏妖、fatalError() 即可。應該避免在退出時寫大段的代碼奖恰,如果確實需要在不同的退出點上編寫退出清理邏輯吊趾,可以考慮使用 defer 來避免重復。

分號

Swift 不需要在一行代碼結束時使用分號瑟啃。只有當你想把多行代碼放在一行寫時论泛,才需要用分號隔開它們,但是一般不推薦這樣做蛹屿。只有在使用 for-conditional-increment 時用到分號是例外屁奏,當然我們更推薦使用 for-in

推薦:

let swift = "not a scripting language"

不推薦:

let swift = "not a scripting language";

圓括號

條件判斷語句外的圓括號不是必須的错负,推薦省略它們坟瓢。

推薦:

if name == "Hello" {
    print("World")
}

不推薦:

if (name == "Hello") {
    print("World")
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市犹撒,隨后出現(xiàn)的幾起案子折联,更是在濱河造成了極大的恐慌,老刑警劉巖识颊,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诚镰,死亡現(xiàn)場離奇詭異,居然都是意外死亡祥款,警方通過查閱死者的電腦和手機清笨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镰踏,“玉大人函筋,你說我怎么就攤上這事〉煳保” “怎么了跌帐?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绊率。 經常有香客問我谨敛,道長,這世上最難降的妖魔是什么滤否? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任脸狸,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘炊甲。我一直安慰自己泥彤,他們只是感情好,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布卿啡。 她就那樣靜靜地躺著吟吝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颈娜。 梳的紋絲不亂的頭發(fā)上剑逃,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音官辽,去河邊找鬼蛹磺。 笑死,一個胖子當著我的面吹牛同仆,可吹牛的內容都是我干的萤捆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乓梨,長吁一口氣:“原來是場噩夢啊……” “哼鳖轰!你這毒婦竟也來了清酥?” 一聲冷哼從身側響起扶镀,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎焰轻,沒想到半個月后臭觉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡辱志,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年蝠筑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揩懒。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡什乙,死狀恐怖,靈堂內的尸體忽然破棺而出已球,到底是詐尸還是另有隱情臣镣,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布智亮,位于F島的核電站忆某,受9級特大地震影響,放射性物質發(fā)生泄漏阔蛉。R本人自食惡果不足惜弃舒,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望状原。 院中可真熱鬧聋呢,春花似錦苗踪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至岖寞,卻和暖如春椒舵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背磨澡。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工碗啄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稳摄。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓稚字,卻偏偏與公主長得像,于是被迫代替她去往敵國和親厦酬。 傳聞我的和親對象是個殘疾皇子胆描,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內容