Swift 一若治、類與結(jié)構(gòu)體(上)

類和結(jié)構(gòu)體.png

一慨蓝、類與結(jié)構(gòu)體

1.1 結(jié)構(gòu)體

結(jié)構(gòu)體:結(jié)構(gòu)體和類十分相似感混,既可以定義屬性,又可以定義方法菌仁,但其不像類一樣具有繼承的特性浩习。
在swift中,使用struct關(guān)鍵字來定義結(jié)構(gòu)體,結(jié)構(gòu)體中可以聲明變量或者常量作為結(jié)構(gòu)體的屬性济丘,也可以創(chuàng)建函數(shù)作為結(jié)構(gòu)體的方法谱秽,結(jié)構(gòu)體使用點語法來調(diào)用其中的屬性和方法。

示例代碼如下:

struct ZZTeacher {

    var age: Int

    var name: String

    init(age: Int, name: String) {

        self.age = age

        self.name = name

    }

}

1.2 類

類的定義:類是編程世界中萬物的抽象摹迷,使用類可以模擬萬物的對象疟赊。
類使用關(guān)鍵字class來聲明

class ZZTeacher {

    var age: Int

    var name: String

    init(age: Int, name: String) {

        self.age = age

        self.name = name

    }

    deinit {

    }

}

1.3 類與結(jié)構(gòu)體的異同

相同點:
1)定義存儲值的屬性
2)定義方法
3)定義下標以使用下標語法提供對其值的訪問
4)定義初始化器
5)使用 extension 來拓展功能
6)遵循協(xié)議來提供某種功能
不同點:
1)類有繼承的特性,而結(jié)構(gòu)體沒有
2)類型轉(zhuǎn)換使您能夠在運行時檢查和解釋類實例的類型
3)類有析構(gòu)函數(shù)用來釋放其分配的資源
4)引用計數(shù)允許對一個類實例有多個引用

1.4 引用類型和值類型

swift語言中的數(shù)據(jù)類型分為值類型引用類型峡碉。結(jié)構(gòu)體近哟、枚舉以及除類以外所有數(shù)據(jù)類型都屬于值類型,只有類是引用類型的鲫寄。值類型數(shù)據(jù)和引用類型數(shù)據(jù)最大的區(qū)別在于當進行數(shù)據(jù)傳遞時吉执,值類型總是被復(fù)制,而引用類型不會被復(fù)制地来,引用類型是通過引用計數(shù)來管理其生命周期的戳玫。

類是引用類型,也就意味著一個類類型的變量并不直接存儲具體的實例對象未斑,而是對當前存儲具體實例內(nèi)存地址的引用咕宿。示例代碼如下:

class ZGTeacher {

    var age: Int

    var name: String

    init(age: Int, name: String) {

        self.age = age

        self.name = name

    }

    deinit {

        

    }

}

var t = ZGTeacher(age: 32, name: "Zhang")

var t1 = t
聲明一個類并復(fù)制給變量t.png
var t1 = t
t1.png

這里我們借助兩個指令來查看當前變量的內(nèi)存結(jié)構(gòu)

po : p 和 po 的區(qū)別在于使用 po 只會輸出對應(yīng)的值,而 p 則會返回值的類型以及命令結(jié)果的引用名蜡秽。

x/8g: 讀取內(nèi)存中的值(8g: 8字節(jié)格式輸出)

t和t1地址打印.png

根據(jù)上圖可以看到府阀,t和t1存儲的是同一實例對象的內(nèi)存地址,但是它們自己的存儲地址是不一樣的芽突。

Swift中有引用類型试浙,就有值類型,最典型的就是 Struct ,結(jié)構(gòu)體的定義也非常簡單寞蚌,相比較類類型的變量中存儲的是地址川队,那么值類型存儲的就是具體的實例(或者說具體的值)

struct ZGTeacher {

    var age: Int

    var name: String

    init(age: Int, name: String) {

        self.age = age

        self.name = name

    }

}


var t = ZGTeacher(age: 32, name: "Zhang")

var t1 = t
t1.age = 20
結(jié)構(gòu)體t和t1.png

讀者在這里需要注意睬澡,如果值類型有數(shù)據(jù)傳遞,原來的實例會被復(fù)制一份眠蚂,修改新的實例并不能修改原始的實例煞聪。

Struct t和Struct t1.png

其實引用類型就相當于 在線的Excel ,當我們把這個鏈接共享給別人的時候逝慧,別人的修改我們是能夠看到的昔脯;值類型就相當于本地的 Excel ,當我們把本地的 Excel 傳遞給別人的時候,就相當于重新復(fù)制了一份給別人啄糙,至于他們對于內(nèi)容的修改我們是無法感知的。

1.5 結(jié)構(gòu)體和類在內(nèi)存中的分布

引用類型和值類型還有一個最直觀的區(qū)別就是存儲的位置不同:一般情況云稚,值類型存儲的在棧上隧饼,引用類型存儲在堆上
首先我們對內(nèi)存區(qū)域來進行一個基本概念的認知静陈,大家看下面這張圖

內(nèi)存分布示例圖.png

棧區(qū)(stack): 局部變量和函數(shù)運行過程中的上下文

func test () {
    ///我們在函數(shù)內(nèi)部聲明的age變量是不是就是一個局部變量
    var age: Int = 32
    print("end")
}

test()
age被分配在棧區(qū).png

Heap: 存儲所有對象
Global: 存儲全局變量燕雁;常量;代碼區(qū)

Segment & Section: Mach-O 文件有多個段( Segment )鲸拥,每個段有不同的功能拐格。然后每個段又分為很多小的 Section

TEXT.text : 機器碼
TEXT.cstring : 硬編碼的字符串
TEXT.const: 初始化過的常量
DATA.data: 初始化過的可變的(靜態(tài)/全局)數(shù)據(jù)
DATA.const: 沒有初始化過的常量
DATA.bss: 沒有初始化的(靜態(tài)/全局)變量
DATA.common: 沒有初始化過的符號聲明

///初始化過的可變的(靜態(tài)/全局)數(shù)據(jù) 
int a = 20;
///沒有初始化過的符號聲明
int age;
int main(int argc, const char * argv[]) {
    @autoreleasepool {
       ///硬編碼的字符串
        char * p = "Zhang";
        NSLog(@"Hello, World!");
    }
    return 0;
}

通過lldb打印地址,和libLGCatAddress.dylib工具可以看到a被放在DATA.data

(lldb) po &a 0x0000000100008020
(lldb) cat address 0x0000000100008020
address:0x0000000100008020, 8a <+0> , External: NO ZGOCTest.__DATA.__data +8

可以看到age被放在DATA.__common

(lldb) po &age 0x0000000100008020
(lldb) cat address 0x0000000100008020
address:0x0000000100008020, 0age <+0> , External: NO ZGOCTest.__DATA.__common +0

可以看到p被放在TEXT.__cstring

po &p 0x00007ff7bfeff2e8
(lldb) x/8g 0x00007ff7bfeff2e8
0x7ff7bfeff2e8: 0x0000000100003f9a 0x00007ff7bfeff440
0x7ff7bfeff2f8: 0x0000000000000001 0x00007ff7bfeff410
0x7ff7bfeff308: 0x00000001000194fe 0x0000000000000000
0x7ff7bfeff318: 0x0000000000000000 0x0000000000000000
(lldb) cat address 0x0000000100003f9a
address:0x0000000100003f9a, 0ZGOCTest.__TEXT.__cstring +0

下面我們看一下結(jié)構(gòu)體和類在內(nèi)存中的分布刑赶。示例代碼如下:

結(jié)構(gòu)體

struct ZGTeacher {
    var age = 18
    var name = "Zhang"
    
}
func test () {
    var t = ZGTeacher()
    print("end")
}

test()

接下來使用命令 frame varibale -L xxx

frame variable -L t
0x00007ff7bfeff2b0: (ZGSwiftTest.ZGTeacher) t = {
0x00007ff7bfeff2b0: age = 18
0x00007ff7bfeff2b8: name = "Zhang"

結(jié)構(gòu)體t在內(nèi)存中的地址為0x00007ff7bfeff2b0,第一個成員變量age的地址正好和結(jié)構(gòu)體的內(nèi)存地址相同捏浊,接下來的8個字節(jié)存放的是另外一個成員變量name。根據(jù)這個打印不難看出結(jié)構(gòu)體在內(nèi)存中的分布情況撞叨,如下圖所示:

結(jié)構(gòu)體在棧上的內(nèi)存分配.png

class ZGperson {
    var age = 18
    var name = "Zhang"
}

struct ZGTeacher {
    var age = 18
    var name = "Zhang"
    var p = ZGperson()
    
}
func test () {
    var t = ZGTeacher()
    print("end")
}

test()

frame variable -L t
0x00007ff7bfeff2b0: (ZGSwiftTest.ZGTeacher) t = {
0x00007ff7bfeff2b0: age = 18
0x00007ff7bfeff2b8: name = "Zhang"
scalar: p = 0x00000001031074c0 {
0x00000001031074d0: age = 18
0x00000001031074d8: name = "Zhang"
}
}

為結(jié)構(gòu)體添加一個引用類型的變量金踪,結(jié)構(gòu)體分配的位置不會發(fā)生改變,還是被分配到棧上牵敷。

class ZGTeacher {
    var age = 18
    var name = "Zhang"
   
    
}
func test () {
///1胡岔、棧上分配8個字節(jié),分配實例對象的引用類型
///2劣领、堆空間上尋找合適的內(nèi)存區(qū)域
///3姐军、將value----拷貝到堆
///4、將棧上空間的地址指向堆區(qū)
    var t = ZGTeacher()
    print("end")
}

test()

(lldb) frame variable -L -t
scalar: (ZGSwiftTest.ZGTeacher) t = 0x0000000101009fd0 {
0x0000000101009fe0: age = 18
0x0000000101009fe8: name = "Zhang"
}
(lldb) cat address 0x0000000101009fd0
address:0x0000000101009fd0, (String) $R0 = "0x101009fd0 heap pointer, (0x30 bytes), zone: 0x7ff859c9e000"

可以看到類是被分配到堆(heap pointer)上的

類在內(nèi)存上的分配.png

1.5 類與結(jié)構(gòu)體的應(yīng)用場景和時間分配

類和結(jié)構(gòu)體有著本質(zhì)的不同尖淘,它們在傳遞數(shù)據(jù)時的機制不同奕锌,分別適用于不同的應(yīng)用場景。蘋果官方推薦開發(fā)者在如下情況使用結(jié)構(gòu)體來描述數(shù)據(jù):

1)要描述的數(shù)據(jù)類型中只有少量的簡單數(shù)據(jù)類型的屬性村生。
2)要描述的數(shù)據(jù)類型在傳遞數(shù)據(jù)時需要以復(fù)制的方式進行惊暴。
3)要描述的數(shù)據(jù)類型中的所有屬性在進行傳遞時需要以復(fù)制的方式進行。
4)不需要繼承另一個數(shù)據(jù)模型

這里我們也可以通過github上StructVsClassPerformance這個案例來直觀的測試當前結(jié)構(gòu)體和類的時間分配趁桃。

我們來看兩個官方案例

案例一:

 import UIKit
enum Color { case blue, green, gray }
enum Orientation { case left, right }
enum Tail { case none, tail, bubble }
var cache = [String : UIImage]()
func makeBallon(_ color : Color, _ orientation: Orientation, _ tail: Tail) -> UIImage {
    let key = "\(color):\(orientation):\(tail)"
    if let image = cache[key] {
        return image
    }
    return UIImage.init()
    }

通過上面的案例代碼可以看到調(diào)用key值會不停的訪問開辟和釋放空間辽话,效率不高,可以進行相關(guān)的優(yōu)化卫病。

 enum Color { case blue, green, gray }
enum Orientation { case left, right }
enum Tail { case none, tail, bubble }
var cache = [String : UIImage]()
struct Ballon: Hashable {
    var color: Color
    var orientation: Orientation
    var tail: Tail
}
func makeBallon(_ ballon: Ballon) -> UIImage {

    if let image = cache[ballon] {
        return image
    }
    return UIImage.init()
    
}

案例二:

struct Attachment {
    let fileURL: URL
    let uuid: String
    let mineType: String
    init?(fileURL: URL, uuid: String, mineType: String) {
        guard mineType.isMineType else {
            return nil
        }
        self.fileURL = fileURL
        self.uuid = uuid
        self.mineType = mimeType
    }
}

可優(yōu)化為:

enum MineType: String {
    case jpeg = "image/jpeg"
    ...
}
struct Attachment {
    let fileURL: URL
    let uuid: UUID
    let mineType: MineType
    init?(fileURL: URL, uuid: UUID, mineType: MineType) {
        guard mineType.isMineType else {
            return nil
        }
        self.fileURL = fileURL
        self.uuid = uuid
        self.mineType = mimeType
    }
}

在實際開發(fā)應(yīng)用時油啤,應(yīng)該盡可能的用值類型替代引用類型,用結(jié)構(gòu)體替代類蟀苛。

二益咬、類的初始化器

在結(jié)構(gòu)體中開發(fā)者并不需要提供構(gòu)造方法,結(jié)構(gòu)體會根據(jù)屬性自動生成一個構(gòu)造方法帜平,而類則要求開發(fā)者自己提供構(gòu)造方法幽告,在init()構(gòu)造方法中梅鹦,需要完成對類中所有屬性的賦值操作。

struct ZGTeacher {

    var age: Int

    var name: String


//    ///如果自己不創(chuàng)建的話冗锁,默認會自動生成的

//    init() {

//

//    }

}

Swift 中創(chuàng)建類和結(jié)構(gòu)體的實例時必須為所有的存儲屬性設(shè)置一個合適的初始值齐唆。所以類 ZGPerson 必須要提供對應(yīng)的指定初始化器,同時我們也可以為當前的類提供便捷初始化器(關(guān)鍵字convenience)(注意:便捷初始化器必須從相同的類里調(diào)用另一個初始化器冻河。)

class ZGPerson {

    var age: Int

    var name: String

    ///_表示匿名函數(shù)

    ///_: 外部變量

    /// age: 內(nèi)部變量

    init(_ age: Int, _ name: String) {

        self.age = age

        self.name = name

    }

    ///便捷初始化器箍邮,必須調(diào)用當前類的其他構(gòu)造方法
    convenience init() {

        self.init(32, "Zhang")

    }

}

當我們派生出一個子類 ZGTeacher ,并指定一個指定初始化器之后會出現(xiàn)什么問題

class ZGTeacher: ZGPerson {

    var subjectName: String

    init(subjectName: String) {

        self.subjectName = subjectName

    }

}

報錯.png

Swift語言中有這樣的原則:

1)指定初始化器必須保證在向上委托給父類初始化器之前,其所在類引入的所有屬性都要初始化完成芋绸。
2)指定初始化器必須先向上委托父類初始化器媒殉,然后才能為繼承的屬性設(shè)置新值。如果不這樣做摔敛,指定初始化器賦予的新值將被父類中的初始化器所覆蓋廷蓉。
3)便捷初始化器必須先委托同類中的其它初始化器,然后再為任意屬性賦新值(包括同類里定義的屬性)马昙。如果沒這么做桃犬,便捷構(gòu)初始化器賦予的新值將被自己類中其它指定初始化器所覆蓋。
4)初始化器在第一階段初始化完成之前行楞,不能調(diào)用任何實例方法攒暇、不能讀取任何實例屬性的值,也不能引用 self 作為值子房。

可失敗初始化器

可失敗構(gòu)造方法的定義十分簡單形用,只需要使用init?()即可

class ZGPerson {

    var age: Int

    var name: String

    //_表示匿名函數(shù)

    //_: 外部變量

    // age: 內(nèi)部變量

    init?(_ age: Int, _ name: String) {

        ///比如這里我們定義了如果小于18就不是一個合法的成年人

        if age < 18 {

            return nil

        }

        self.age = age

        self.name = name

    }

    ///便捷初始化器,必須調(diào)用當前類的其他構(gòu)造方法

    convenience init?() {

        self.init(32, "Zhang")

    }

}

必要初始化器
另外证杭,開發(fā)者也可以設(shè)置某些構(gòu)造方法為必要構(gòu)造方法田度,如果一個類中的某些構(gòu)造方法被指定為必要構(gòu)造方法,則其子類必須實現(xiàn)這個構(gòu)造方法(可以通過繼承或者覆寫的方式)解愤,必要構(gòu)造方法需要使用required關(guān)鍵字進行修飾镇饺,示例代碼如下:

class ZGPerson {

    var age: Int

    var name: String

    //_表示匿名函數(shù)

    //_: 外部變量

    // age: 內(nèi)部變量

    required init(_ age: Int, _ name: String) {

        self.age = age

        self.name = name

    }

    ///便捷初始化器,必須調(diào)用當前類的其他構(gòu)造方法

    convenience init() {

        self.init(32, "Zhang")

    }

}

class ZGTeacher: ZGPerson {

    var subjectName: String

    init(subjectName: String) {

        self.subjectName = subjectName

        super.init(18, "Zhang")

    }
///如果在子類沒有提供就會報錯
    

}

三送讲、類的生命周期

iOS開發(fā)的語言不管是OC還是Swift后端都是通過LLVM進行編譯的奸笤,如下圖所示:

LLVM.png

OC 通過 clang 編譯器,編譯成 IR哼鬓,然后再生成可執(zhí)行文件 .o(這里也就是我們的機器碼)
Swift 則是通過 Swift 編譯器編譯成 IR监右,然后再生成可執(zhí)行文件。

IR.png

// 分析輸出AST
swiftc main.swift -dump-parse
// 分析并且檢查類型輸出AST
swiftc main.swift -dump-ast
// 生成中間體語言(SIL)异希,未優(yōu)化
swiftc main.swift -emit-silgen
// 生成中間體語言(SIL)秸侣,優(yōu)化后的
swiftc main.swift -emit-sil
// 生成LLVM中間體語言 (.ll文件)
swiftc main.swift -emit-ir
// 生成LLVM中間體語言 (.bc文件)
swiftc main.swift -emit-bc
// 生成匯編
swiftc main.swift -emit-assembly
// 編譯生成可執(zhí)行.out文件
swiftc -o main.o main.swift

SIL文件讀取分析

@main: 入口函數(shù), @為標識
%0: 寄存器,虛擬的味榛,真的寄存器
xcrun swift-demangle 反編譯

Swift 對象內(nèi)存分配:

__allocating_init -----> swift_allocObject -----> swift_allocObject
-----> swift_slowAlloc -----> Malloc

Swift 對象的內(nèi)存結(jié)構(gòu) HeapObject (OC objc_object) ,有兩個屬性:
一個是Metadata 予跌,一個是 RefCount搏色,默認占用 16 字節(jié)大小。

objc_object {
isa
}

源碼中 kind種類

kind種類.png

struct HeapObject {
    var metadata: UnsafeRawPointer
    var refcounted1: UInt32
    var refcounted2: UInt32
}

struct Metadata {

    var kind: Int

    var superClass: Any.Type

    var cacheData: (Int, Int)

    var data: Int

    var classFlags: Int32

    var instanceAddressPoint: UInt32

    var instanceSize: UInt32

    var instanceAlignmentMask: UInt16

    var reserved: UInt16

    var classSize: UInt32

    var classAddressPoint: UInt32

    var typeDescriptor: UnsafeMutableRawPointer

    var iVarDestroyer: UnsafeRawPointer

}

class ZGTeacher {
    var age: Int = 18
    var name: String = "Zhang"
}

var t = ZGTeacher()
let objcRawPtr = Unmanaged.passUnretained(t as AnyObject).toOpaque()
let objcPtr = objcRawPtr.bindMemory(to: HeapObject.self, capacity: 1)
print(objcPtr.pointee)
let metadata = objcPtr.pointee.metadata.bindMemory(to: Metadata.self, capacity: MemoryLayout<Metadata>.stride).pointee
print(metadata)

HeapObject(metadata: 0x00000001000081a8, refcounted1: 3, refcounted2: 0)
Metadata(kind: 4295000432, superClass: _TtCs12_SwiftObject, cacheData: (140703534573568, 140943646785536), data: 4302469682, classFlags: 2, instanceAddressPoint: 0, instanceSize: 40, instanceAlignmentMask: 7, reserved: 0, classSize: 168, classAddressPoint: 16, typeDescriptor: 0x0000000100003c6c, iVarDestroyer: 0x0000000000000000)

經(jīng)過源碼分析和數(shù)據(jù)類型的重綁定,我們不難得出 swift 類的數(shù)據(jù)結(jié)構(gòu)

struct Metadata {

    var kind: Int

    var superClass: Any.Type

    var cacheData: (Int, Int)

    var data: Int

    var classFlags: Int32

    var instanceAddressPoint: UInt32

    var instanceSize: UInt32

    var instanceAlignmentMask: UInt16

    var reserved: UInt16

    var classSize: UInt32

    var classAddressPoint: UInt32

    var typeDescriptor: UnsafeMutableRawPointer

    var iVarDestroyer: UnsafeRawPointer

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末券册,一起剝皮案震驚了整個濱河市频轿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烁焙,老刑警劉巖航邢,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骄蝇,居然都是意外死亡膳殷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門九火,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赚窃,“玉大人,你說我怎么就攤上這事岔激±占” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵虑鼎,是天一觀的道長辱匿。 經(jīng)常有香客問我,道長炫彩,這世上最難降的妖魔是什么匾七? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮媒楼,結(jié)果婚禮上乐尊,老公的妹妹穿的比我還像新娘。我一直安慰自己划址,他們只是感情好扔嵌,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著夺颤,像睡著了一般痢缎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上世澜,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天独旷,我揣著相機與錄音,去河邊找鬼。 笑死嵌洼,一個胖子當著我的面吹牛案疲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播麻养,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼褐啡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鳖昌?” 一聲冷哼從身側(cè)響起备畦,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎许昨,沒想到半個月后懂盐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡糕档,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年莉恼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翼岁。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡类垫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出琅坡,到底是詐尸還是另有隱情悉患,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布榆俺,位于F島的核電站售躁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏茴晋。R本人自食惡果不足惜陪捷,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诺擅。 院中可真熱鬧市袖,春花似錦、人聲如沸烁涌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撮执。三九已至微峰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抒钱,已是汗流浹背蜓肆。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工颜凯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仗扬。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓症概,卻偏偏與公主長得像,于是被迫代替她去往敵國和親厉颤。 傳聞我的和親對象是個殘疾皇子穴豫,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

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