Swift 关键字

deinit: 当一个类的实例即将被销毁时,会调用这个方法。

class Person  
{  
    var name:String  
    var age:Int  
    var gender:String

    deinit  
    {  
        //从堆中释放,并释放的资源
    }  
}

extension:允许给已有的类、结构体、枚举、协议类型,添加新功能。

class Person  
{  
    var name:String = ""  
    var age:Int = 0  
    var gender:String = ""  
}

extension Person  
{  
    func printInfo()  
    {  
        print("My name is \(name), I'm \(age) years old and I'm a \(gender).")  
    }  
}

fileprivate:访问控制权限,只允许在定义源文件中访问。

class Person  
{  
    fileprivate var jobTitle:String = ""  
}

extension Person  
{
    //当 extension 和 class 在同一个文件中时,允许访问
    func printJobTitle()  
    {  
        print("My job is (jobTitle)")  
    }  
}

inout:将一个值传入函数,并可以被函数修改,然后将值传回到调用处,来替换初始值。适用于引用类型和值类型。 其实就是声明参数为指针

func dangerousOp(_ error:inout NSError?)  
{  
    error = NSError(domain: "", code: 0, userInfo: ["":""])  
}

var potentialError:NSError?
dangerousOp(&potentialError)

//代码运行到这里,potentialError 不再是 nil,而是已经被初始化

internal:访问控制权限,允许同一个模块下的所有源文件访问,如果在不同模块下则不允许访问。

open:访问控制权限,允许在定义的模块外也可以访问源文件里的所有类,并进行子类化。对于类成员,允许在定义的模块之外访问和重写。

open var foo:String? //这个属性允许在 app 内或 app 外重写和访问。在开发框架的时候,会应用到这个访问修饰符。

private:访问控制权限,只允许实体在定义的类以及相同源文件内的 extension 中访问。

class Person  
{  
    private var jobTitle:String = ""  
}

// 当 extension 和 class 不在同一个源文件时
extension Person  
{
    // 无法编译通过,只有在同一个源文件下才可以访问
    func printJobTitle()  
    {  
        print("My job is (jobTitle)")  
    }  
}

public:访问控制权限,允许在定义的模块外也可以访问源文件里的所有类,但只有在同一个模块内可以进行子类化。对于类成员,允许在同个模块下访问和重写。

public var foo:String? //只允许在 app 内重写和访问。

static:用于定义类方法,在类型本身进行调用。此外还可以定义静态成员。

class Person  
{  
    var jobTitle:String?

    static func assignRandomName(_ aPerson:Person)  
    {  
        aPerson.jobTitle = "Some random job"  
    }  
}

let somePerson = Person()  
Person.assignRandomName(somePerson)  
//somePerson.jobTitle 的值是 "Some random job"

struct:通用、灵活的结构体,是程序的基础组成部分,并提供了默认初始化方法。与 class 不同,当 struct 在代码中被传递时,是被拷贝的,并不使用引用计数。除此之外,struct 没有下面的这些功能:

  • 使用继承。
  • 运行时的类型转换。
  • 使用析构方法。
struct Person  
{  
    var name:String  
    var age:Int  
    var gender:String  
}

typealias:给代码中已经存在的类,取别名。

typealias JSONDictionary = [String: AnyObject]

func parseJSON(_ deserializedData:JSONDictionary){}

defer:用于在程序离开当前作用域之前,执行一段代码。

关闭文件

func foo() {
  let fileDescriptor = open(url.path, O_EVTONLY)
  defer {
    close(fileDescriptor)
  }
  // use fileDescriptor...
}

加/解锁:下面是 swift 里类似 Objective-C 的 synchronized block 的一种写法,可以使用任何一个 NSObject 作 lock

func foo() {
  objc_sync_enter(lock)
  defer { 
    objc_sync_exit(lock)
  }
  // do something...
}

defer 的执行时机:
defer 的执行时机紧接在离开作用域之后,但是是在其他语句之前。这个特性为 defer 带来了一些很“微妙”的使用方式。比如从 0 开始的自增:

class Foo {
    var num = 0
    func foo() -> Int {
        defer { num += 1 }
        return num
    }
    
    // 没有 `defer` 的话我们可能要这么写
    // func foo() -> Int {
    //    num += 1
    //    return num - 1
    // }
}

let f = Foo()
f.foo() // 0
f.foo() // 1
f.num   // 2

fallthrough:显式地允许从当前 case 跳转到下一个相邻 case 继续执行代码。

let box = 1

switch box  
{  
    case 0:  
    print("Box equals 0")  
    fallthrough  
    case 1:  
    print("Box equals 0 or 1")  
    default:  
    print("Box doesn't equal 0 or 1")  
}

guard:当有一个以上的条件不满足要求时,将离开当前作用域。同时还提供解包可选类型的功能。

private func printRecordFromLastName(userLastName: String?)
{  
    guard let name = userLastName, name != "Null" else  
    {  
        //userLastName = "Null",需要提前退出
        return  
    }

    //继续执行代码
    print(dataStore.findByLastName(name))  
}

1.guard关键字必须使用在函数中。
2.guard关键字必须和else同时出现。
3.guard关键字只有条件为false的时候才能走else语句 相反执行后边语句。

repeat:在使用循环的判断条件之前,先执行一次循环中的代码。

repeat  
{  
    print("Always executes at least once before the condition is considered")  
}  
while 1 > 2

where:要求关联类型必须遵守特定协议,或者类型参数和关联类型必须保持一致。也可以用于在 case 中提供额外条件,用于满足控制表达式。

  • 增加判断条件
for i in 0…3 where i % 2 == 0  
{  
    print(i) //打印 0 和 2  
}
  • 协议使用where, 只有基类实现了当前协议才能添加扩展。 换个说法, 多个类实现了同一个协议,该语法根据类名分别为这些类添加扩展, 注意是分别(以类名区分)!!!
protocol SomeProtocol {
    func someMethod()
}
 
class A: SomeProtocol {
    let a = 1
    
    func someMethod() {
       print("call someMethod")
    }
}
 
class B {
    let a = 2
}
 
//基类A继承了SomeProtocol协议才能添加扩展
extension SomeProtocol where Self: A {
    func showParamA() {
        print(self.a)
    }
}
//反例,不符合where条件
extension SomeProtocol where Self: B {
    func showParamA() {
        print(self.a)
    }
}
let objA = A()
let objB = B()  //类B没实现SomeProtocol, 所有没有协议方法
objA.showParamA()  //输出1

as:类型转换运算符,用于尝试将值转成其它类型。

  • as : 数值类型转换
let age = 28 as Int
let money = 20 as CGFloat
let cost = (50 / 2) as Double
switch person1 { 
  case let person1 as Student: 
    print("是Student类型,打印学生成绩单...") 
  case let person1 as Teacher: 
    print("是Teacher类型,打印老师工资单...") 
  default: break
}
  • as!:向下转型(Downcasting)时使用。由于是强制类型转换,如果转换失败会报 runtime 运行错误。
let person : Person = Teacher("Jimmy Lee")
let jimmy = person as! Teacher
  • as?: as? 和 as! 操作符的转换规则完全一样。但 as? 如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值。由于 as? 在转换失败的时候也不会出现错误,所以对于如果能确保100%会成功的转换则可使用 as!,否则使用 as?
let a = 13 as! String
print(a)
//会crash
let a = 13 as? String
print(a)
//输出为nil

is:类型检查运算符,用于确定实例是否为某个子类类型。

class Person {}  
class Programmer : Person {}  
class Nurse : Person {}

let people = [Programmer(), Nurse()]

for aPerson in people  
{  
    if aPerson is Programmer  
    {  
        print("This person is a dev")  
    }  
    else if aPerson is Nurse  
    {  
        print("This person is a nurse")  
    }  
}

nil:在 Swift 中表示任意类型的无状态值。

Swift的nil和OC中的nil不一样.在OC中,nil是一个指向不存在对象的指针.而在Swift中,nil不是指针,它是一个不确定的值.用来表示值缺失.任何类型的optional都可以被设置为nil. 而在OC中,基本数据类型和结构体是不能被设置为nil的. 给optional的常量或者变量赋值为nil.来表示他们的值缺失情况.一个optional常量或者变量如果在初始化的时候没有被赋值,他们自动会设置成nil.

class Person{}  
struct Place{}

//任何 Swift 类型或实例可以为 nil
var statelessPerson:Person? = nil  
var statelessPlace:Place? = nil  
var statelessInt:Int? = nil  
var statelessString:String? = nil

super:在子类中,暴露父类的方法、属性、下标。

class Person  
{  
    func printName()  
    {  
        print("Printing a name. ")  
    }  
}

class Programmer : Person  
{  
    override func printName()  
    {  
        super.printName()  
        print("Hello World!")  
    }  
}

let aDev = Programmer()  
aDev.printName() //打印 Printing a name. Hello World!

self:任何类型的实例都拥有的隐式属性,等同于实例本身。此外还可以用于区分函数参数和成员属性名称相同的情况。

class Person  
{  
    func printSelf()  
    {  
        print("This is me: (self)")  
    }  
}

let aPerson = Person()  
aPerson.printSelf() //打印 "This is me: Person"

Self:在协议中,表示遵守当前协议的实体类型。

protocol Printable  
{  
    func printTypeTwice(otherMe:Self)  
}

struct Foo : Printable  
{  
    func printTypeTwice(otherMe: Foo)  
    {  
        print("I am me plus (otherMe)")  
    }  
}

let aFoo = Foo()  
let anotherFoo = Foo()

aFoo.printTypeTwice(otherMe: anotherFoo) //打印 I am me plus Foo()

_:用于匹配或省略任意值的通配符。

for _ in 0..<3  
{  
    print("Just loop 3 times, index has no meaning")  
}

另外一种用法:

let _ = Singleton() //忽略不使用的变量

以#开头的关键字


#available:基于平台参数,通过 if,while,guard 语句的条件,在运行时检查 API 的可用性。
if #available(iOS 10, *)  
{  
    print("iOS 10 APIs are available")  
}
#colorLiteral:在 playground 中使用的字面表达式,用于创建颜色选取器,选取后赋值给变量。
let aColor = #colorLiteral //创建颜色选取器

#column:一种特殊的字面量表达式,用于获取字面量表示式的起始列数。
class Person  
{  
    func printInfo()  
    {  
        print("Some person info - on column (#column)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - on column 53
#function:特殊字面量表达式,返回函数名称。在方法中,返回方法名。在属性的 getter 或者 setter 中,返回属性名。在特殊的成员中,比如 init 或 subscript 中,返回关键字名称。在文件的最顶层时,返回当前所在模块名称。
class Person  
{  
    func printInfo()  
    {  
        print("Some person info - inside function (#function)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - inside function printInfo()
#line:特殊字面量表达式,用于获取当前代码的行数。
class Person  
{  
    func printInfo()  
    {  
        print("Some person info - on line number (#line)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - on line number 5
#selector:用于创建 Objective-C selector 的表达式,可以静态检查方法是否存在,并暴露给 Objective-C。
//静态检查,确保 doAnObjCMethod 方法存在  
control.sendAction(#selector(doAnObjCMethod), to: target, forEvent: event)


convenience:

在 Swift 中,为保证安全性,init 方法只能调用一次,且在 init 完成后,保证所有非 Optional 的属性都已经被初始化。

每个类都有指定的初始化方法:designated initializer,这些初始化方法是子类必须调用的,为的就是保证父类的属性都初始化完成了。

而如果不想实现父类的 designated initializer,可以添加 convenience 关键字,自己实现初始化逻辑。
convenience 初始化不能调用父类的初始化方法,只能调用同一个类中的 designated initializer。
由于 convenience 初始化不安全,所以 Swift 不允许 convenience initializer 被子类重写,限制其作用范围。

class People {
    
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

通过extension给原有的People类增加init方法:

// 使用convenience增加init方法
extension People {
    convenience init(smallName: String) {
        self.init(name: smallName)
    }
}

结下来,Student类继承父类People

class Student: People {
    var grade: Int
    
    init(name: String, grade: Int) {
        self.grade = grade
        super.init(name: name)
        // 无法调用
        // super.init(smallName: name)
    }
    
    // 可以被重写 
    override init(name: String) {
        grade = 1
        super.init(name: name)
    }
    
    // 无法重写,编译不通过
    override init(smallName: String) {
        grade = 1
        super.init(smallName: smallName)
    }
}

子类对象调用父类的convenience的init方法:只要在子类中实现重写了父类convenience方法所需要的init方法的话,我们在子类中就可以使用父类的convenience初始化方法了

class People {
    
    var name: String
    
    init(name: String) {
        self.name = name
    }
}
// 使用convenience增加init方法
extension People {
    convenience init(smallName: String) {
        self.init(name: smallName)
    }
}


// 子类
class Teacher: People {
    
    var course: String
    
    init(name: String, course: String) {
        self.course = course
        super.init(name: name)
    }
    
    override init(name: String) {
        self.course = "math"
        super.init(name: name)
    }
}

// 调用convenience的init方法
let xiaoming = Teacher(smallName: "xiaoming")
  • 总结:子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。

required关键字

对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写。
required修饰符的使用规则:

  • required修饰符只能用于修饰类初始化方法。
  • 当子类含有异于父类的初始化方法时(初始化方法参数类型和数量异于父类),子类必须要实现父类的required初始化方法,并且也要使用required修饰符而不是override。
  • 当子类没有初始化方法时,可以不用实现父类的required初始化方法。

代码:

        class MyClass {
            var str:String
            required init(str:String) {
                self.str = str
            }
        }
        class MySubClass:MyClass
        {
            init(i:Int) {
                super.init(str:String(i))
            }
            
        }
        // 编译错误
        MySubClass(i: 123)

会报错,因为你没有实现父类中必须实现的方法。正确的写法:

    class MyClass{
        var str: String?
        required init(str: String?) {
            self.str = str
        }
    }
    class MySubClass: MyClass{
        init(i: Int) {
            super.init(str: String(i))
        }
        
        required init(str: String?) {
            fatalError("init(str:) has not been implemented")
        }
    }

从上面的代码中,不难看出子类需要添加异于父类的初始化方法,必须要重写有required的修饰符的初始化方法,并且也要使用required修饰符而不是override,请千万注意!

如果子类中并没有不同于父类的初始化方法,Swift会默认使用父类的初始化方法:

    class MyClass{
        var str: String?
        required init(str: String?) {
            self.str = str
        }
    }
    class MySubClass: MyClass{
    }
    var MySubClass(str: "hello swift")

在这种情况下,编译器不会报错,因为如果子类没有任何初始化方法时,Swift会默认使用父类的初始化方法。

dynamic && @objc

1.@objc

OC 是基于运行时,遵循了 KVC 和动态派发,而 Swift 为了追求性能,在编译时就已经确定,而不需要在运行时的,在 Swift 类型文件中,为了解决这个问题,需要暴露给 OC 使用的任何地方(类,属性,方法等)的生命前面加上 @objc 修饰符
如果用 Swift 写的 class 是继承 NSObject 的话, Swift 会默认自动为所有非 private 的类和成员加上@objc

在Swift中,我们在给button添加点击事件时,对应的点击事件的触发方法就需要用@objc来修饰

2. dynamic

Swift 中的函数可以是静态调用,静态调用会更快。当函数是静态调用的时候,就不能从字符串查找到对应的方法地址了。这样 Swift 跟 Objective-C 交互时,Objective-C 动态查找方法地址,就有可能找不到 Swift 中定义的方法。

这样就需要在 Swift 中添加一个提示关键字,告诉编译器这个方法是可能被动态调用的,需要将其添加到查找表中。这个就是关键字 dynamic 的作用。

willSet与didSet

  • willSet在设置新的值之前调用。willSet可以带一个newName的参数,没有的话,该参数默认命名为newValue
  • didSet在新的值被设置之后立即调用。didSet可以带一个oldName的参数,表示旧的属性,不带的话默认命名为oldValue
  • willSet和didSet观察器在属性初始化过程中不会被调用。只有在初始化上下文之外,当设置属性值时才会调用。
  • 即使是设置的值和原来值相同,willSet和didSet也会被调用
var counter: Int = 0{
        willSet(newTotal){
            print("计数器: \(newTotal)")
        }
        didSet{
            if counter > oldValue {
                print("新增数 \(counter - oldValue)")
            }
        }
    }
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
//结果:
//计数器: 100
//新增数 100
//计数器: 800
//新增数 700

final

  • final修饰符只能修饰类,表明该类不能被其他类继承,也就是它没资格当父类。
  • final修饰符也可以修饰类中的属性、方法和下标,但前提是该类并没有被final修饰过。
  • final不能修饰结构体和枚举。

final正确的使用场景 - 权限控制
也就是说这个类或方法不希望被继承和重写,具体情况如下:

  • 类或者方法的功能确实已经完备了
    这种通常是一些辅助性质的工具类或者方法,特别那种只包含类方法而没有实例方法的类。比如MD5加密类这种,算法都十分固定,我们基本不会再继承和重写。

  • 避免子类继承和修改造成危险
    有些方法如果被子类继承重写会造成破坏性的后果,导致无法正常工作,则需要将其标为final加以保护。

  • 为了让父类中某些代码一定会执行
    父类的方法如果想要其中一些关键代码在继承重写后仍必须执行(比如状态配置、认证等)。我们可以把父类的方法定义成final,同时将内部可以继承的部分剥离出来,供子类继承重写。下面通过一段代码演示:

class Parent {
   final func method1() {
       //权限验证(必须执行)
       //.....
        
       method2()
        
       //下面是日志记录(必须执行)
       //..........
   }
    
   func method2(){
       //父类的实现
       //......
   }
}

class Child : Parent {
   //只能重写父类的method2方法,不能重写method1方法
   override func method2() {
       //子类的实现
       //......
   }
}

indirect

指明在枚举类型中,存在成员使用相同枚举类型的实例作为关联值的情况。

indirect enum Entertainment  
{  
   case eventType(String)  
   case oneEvent(Entertainment)  
   case twoEvents(Entertainment, Entertainment)  
}

let dinner = Entertainment.eventType("Dinner")  
let movie = Entertainment.eventType("Movie")

let dateNight = Entertainment.twoEvents(dinner, movie)

lazy

指明属性的初始值,直到第一次被使用时,才进行初始化。

class Person  
{  
    lazy var personalityTraits = {  
        //昂贵的数据库开销  
        return ["Nice", "Funny"]  
    }()  
}
let aPerson = Person()  
aPerson.personalityTraits //当 personalityTraits 首次被访问时,数据库才开始工作

mutating

在Swift中,包含三种类型(type): structure,enumeration,class
其中structure和enumeration是值类型(value type),class是引用类型(reference type)
Swift中protocol的功能比OC中强大很多,不仅能再class中实现,同时也适用于struct、enum。但是struct、enum都是值类型,每个值都是有默认的,所以在实例方法中不能改变,因此就要用mutating关键字,这个关键字可以让在此方法中值的改变,会返回到原始结构里边

protocol Vehicle {
    var numberOfWheels: Int {get}
    var color: UIColor {get set}
    mutating func changeColor()
}

struct MyCar: Vehicle {
    let numberOfWheels = 4
    var color = UIColor.blue
    mutating func changeColor() {
        color = .red
    }
}

subscript

  • 下标(subscript)在数组和字典中使用,但是你可以给任何类型(枚举,结构体,类)增加 下标subscript 的功能;
  • subscript的语法类似实例方法、计算属性,其本质就是方法;
struct Person {
    var age = 0
    var no  = 0
    subscript(index: Int) -> Int {
        set {
            if index == 0 {
                age = newValue
            } else {
                no = newValue
            }
        }
        get {
            if index == 0 {
                return age
            } else {
                return no
            }
        }
    }
}

var p = Person()
p[0] = 10
p[1] = 20

print(p.age)  // 10
print(p[0])   // 10

print(p.no)  // 20
print(p[1])  // 20
  • subscript 的返回值类型决定了:
    1.get 方法的返回值类型;
    2.set 方法中 newValue 的类型;
  • subscript 可以接受多个参数,并且是任意类型;
  • subscript 可以没有 set 方法,但必须要有 get 方法;
  • 如果只有 get 方法,可以省略;
struct Person {
    var age = 30

    subscript(index: Int) -> Int {
        if index == 0 {
            return age
        } else {
            return age * 2
        }
    }
}

var p = Person()
print(p[0])  // 30
print(p[1])  // 60

nonmutating

nonmutating关键字,一般配合set使用。如

protocol Settings {
    subscript(key: String) -> AnyObject? { get nonmutating set }
}

它告诉编译器不会修改实例内部的值,也就是set时,不会改变任何其他的变量。

struct Test2 {
    
    var b: Int {
        get {
            return  2
        }
        nonmutating set {
            print("\(newValue)")
        }
    }
}

let t = Test2()
t.b = 3
print(t.b)

optional

用于指明协议中的可选方法。遵守该协议的实体类可以不实现这个方法。

@objc protocol Foo  
{  
    func requiredFunction()  
    @objc optional func optionalFunction()  
}

class Person : Foo  
{  
    func requiredFunction()  
    {  
        print("Conformance is now valid")  
    }  
}

override

指明子类会提供自定义实现,覆盖父类的实例方法、类型方法、实例属性、类型属性、下标。如果没有实现,则会直接继承自父类。

class Person  
{  
    func printInfo()  
    {  
        print("I'm just a person!")  
    }  
}

class Programmer : Person  
{  
    override func printInfo()  
    {  
        print("I'm a person who is a dev!")  
    }  
}

let aPerson = Person()  
let aDev = Programmer()

aPerson.printInfo() //打印 I'm just a person!  
aDev.printInfo() //打印 I'm a person who is a dev!

unowned && weak

  • weak:弱引用对象的引用计数不会+1, 必须为可选类型变量
    在声明弱引用对象是必须用var关键字, 不能用let.
    因为弱引用变量在没有被强引用的条件下会变为nil, 而let常量在运行的时候不能被改变.
class XDTest {
    //会报错
    weak let tentacle = Tentacle() //let is a constant! All weak variables MUST be mutable.
}
  • unowned:相当于__unsafe_unretained, 不安全. 必须为非可选类型.
    unowned引用是non-zeroing(非零的), 在ARC销毁内存后,不会被赋为nil, 这表示着当一个对象被销毁时, 它指引的对象不会清零. 也就是说使用unowned引用在某些情况下可能导致dangling pointers(野指针). 所以在访问无主引用的时候,要确保其引用正确,不然会引起内存崩溃.

throw && rethrow

  • throws的使用很简单,只需要在可能出现异常的函数或者方法后面添加throws。
    经过这个关键字修饰的函数,在调用的时候,需要程序员加上do-catch来调用.

  • rethrows是异常往上传递的关键字。上面说了throws用在可能出现异常的函数或者方法中,而rethrows针对的不是函数或者方法的本身,而是它携带的闭包类型的参数,当它的闭包类型的参数throws的时候,我们要使用rethrows继续将这个异常往上传递, 直到被调用者使用到。这相比throws多一个传递的环节。

@dynamicMemberLookup

这个特性中文可以叫动态查找成员。在使用@dynamicMemberLookup标记了对象后(对象、结构体、枚举、protocol),实现了subscript(dynamicMember member: String)方法后我们就可以访问到对象不存在的属性。如果访问到的属性不存在,就会调用到实现的 subscript(dynamicMember member: String)方法,key 作为 member 传入这个方法。

@dynamicMemberLookup
struct Person {
   subscript(dynamicMember member: String) -> String {
       let properties = ["nickname": "Zhuo", "city": "Hangzhou"]
       return properties[member, default: "undefined"]
   }
}

//执行以下代码
let p = Person()
print(p.city)
print(p.nickname)
print(p.name)
image.png

@autoclosure,他可以让我们的表达式自动封装成一个闭包。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Swift官方文档的词汇结构中, 有非常多的关键字, 它们被用于声明中、语句中、表达式中、类中、模式中, 还有以数...
    小宇宙_fly阅读 751评论 0 3
  • 作者:Jordan Morgan,原文链接,原文日期:2017-02-11 译者:郑一一;校对:numbbbbb,...
    iOS亮子阅读 640评论 0 1
  • 有句话之前我提过,今天还想再说一次。那就是打铁还需自身硬。对于自身能力的严格要求,可以帮助实现我们所有梦寐以求的东...
    苹果上的小豌豆阅读 2,133评论 0 7
  • ? ! ? Swift是一个强类型语言,它希望在编译器做更多的安全检查,所以引入了类型判断。而在类型判断上如果...
    HuangJn阅读 783评论 0 1
  • 2017年3月30日第一次更新 一.用作声明的关键字: class、deinit、enum、extension、f...
    RaInVis阅读 516评论 0 2