[关闭]
@wpaladins 2017-10-05T00:02:22.000000Z 字数 5404 阅读 1795

《The Swift Progremming Language 3.0中文版》读书笔记

笔记


Swift语言代码书写规范说明

欢迎使用Swift

1. 声明常量:let,默认自动推断类型,可以使用“:typename”在变量后面声明类型:

  1. let explicitDouble: Double

2. 值永远不会被隐式转换为其他类型。

如果要转换成字符串也可以像下面这样,便于将字符串变量的值嵌入字符串中输出:

  1. let label = "the width is "
  2. let width = 94
  3. let widthlabel = label + "\(width)"

3. 创建一个空数组或者字典:

  1. let emptyArray = [String]()
  2. let emptyDictionary = [String:Float]()

如果类型信息可以被推断出来。。。

4. 控制流

5. nil、NSNull、Nil、NULL的区别

6. 使用if let 来处理值确实的情况:

  1. var optionalString: String? = "Hello"
  2. print(optionalString == nil)//false
  3. var optionalName: String? = nil
  4. var greeting = "Hello!"
  5. if let name = optionalName {
  6. greeting = "Hello, \(name)"
  7. } else {
  8. greeting = "Hello, Tom"
  9. }

如果变量的可选值是,条件会判断为,大括号中的代码会被跳过。如果不是,会将值解包并赋给后面的常量,这样代码块中就可以使用这个值了。

另外一种处理可选值的方法是通过??操作符来提供一个默认值:

  1. let nickName:String? = nil
  2. let fullName:String = "John Appleseed"
  3. let informalGreeding = "Hi \(nickName ?? fullName)"

7. switch支持任意类型的数据以及各种比较操作-不仅仅是整数以及测试相等:

  1. let vegetable = "red pepper"
  2. switch vegetable {
  3. case let x where x.hasSuffix("pepper")://高端操作
  4. print("Is it a spicy \(x)?")
  5. default:
  6. print("Everything tastes good in soup.")
  7. }

无需break语句。

8. 使用..<创建范围,创建的范围不包含上界,如果想包含的话需要使用...

9. 函数

1. 使用func来声明一个函数,使用名字和参数来调用函数。使用->来指定函数返回值的类型:

  1. func greet(person: String, day: String) -> String {
  2. return "Hello \(person), today is \(day)."
  3. }
  4. greet(person: "Bob", day: "Tuesday")

2. 函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式:

  1. func sumOf(numbers: Int...) -> Int {
  2. var sum = 0
  3. for number in numbers {
  4. sum += number
  5. }
  6. return sum
  7. }
  8. sumOf()
  9. sumOf(numbers: 42, 57, 1)

3. 函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,可以使用嵌套函数重构一个太长或者太复杂的函数。

4. 函数是第一等类型,这意味着函数可以作为另一个函数的返回值:

  1. func makeIncrementer() -> ((Int) -> Int) {
  2. func addOne(number: Int) -> Int {
  3. return 1 + number
  4. }
  5. return addOne
  6. }
  7. var incrementer = makeIncrementer()
  8. incrementer(7)

5. 函数也可以当做参数传入另一个函数:

  1. func hasAnyMatches(List: [Int], condition: (Int) -> Bool) -> Bool {
  2. for item in List {
  3. if condition(item) {
  4. return true
  5. }
  6. }
  7. return false
  8. }
  9. func lessThanTen(number: Int) -> Bool {
  10. return number < 10
  11. }
  12. hasAnyMatches(List: [20, 19, 70, 12], condition: lessThanTen)//只写函数名

10. 闭包

函数实际上是一种特殊的闭包:它是一段能之后被调取的代码。闭包中的代码能访问闭包所建作用域中能得到的变量和函数,即使闭包是在一个不同的作用域被执行的---你已经在嵌套函数例子中所看到。你可以使用{}来创建一个匿名闭包。使用in将参数和返回值类型声明与闭包函数体进行分离。

  1. let numbers = [76, 24]
  2. numbers.map({
  3. (number: Int) -> Int in
  4. let result = 3 * number
  5. return result
  6. })

有很多种创建更简洁的闭包的方法。如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当做结果返回。

  1. let mappedNumbers = numbers.map({number in 3 * number})
  2. print(mappedNumbers)

你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数,你可以完全忽略括号。

  1. let sortedNumbers = numbers.sorted {$0 > $1}
  2. print(sortedNumbers)

11. 类和对象

使用init来创建一个构造器。

  1. class NamedShape {
  2. var numberOfSides = 0
  3. var name: String
  4. init(name: String) {
  5. self.name = name
  6. }
  7. func simpleDescription() -> String {
  8. return "A shape with \(numberOfSides) sides"
  9. }
  10. }

注意self被用来区别实例变量。
使用deinit创建一个析构函数。

1. 父类

子类如果要重写父类的方法的话,需要用 override 标记——如果没有添加 override 就重写父类方法的话编译器 会报错。编译器同样会检测 override 标记的方法是否确实在父类中。

2. 属性

除了储存简单的属性之外,属性可以有gettersetter

  1. class EquilateralTriangle: namedShape {
  2. var sideLength: Double = 0.0
  3. init(sideLength: Double, name: String) {
  4. self.sideLength = sideLength
  5. super.init(name: name)
  6. numberOfSides = 3
  7. }
  8. var perimeter: Double {
  9. get {
  10. return 3.0 * sideLength
  11. }
  12. set {
  13. sideLength = newValue / 3.0//
  14. }
  15. }
  16. override func simpleDescription() -> String {
  17. return "An equilateral triagle with sides of length \(sideLength)."
  18. }
  19. }
  20. var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
  21. print(triangle.perimeter)
  22. triangle.perimeter = 9.9
  23. print(triangle.sideLength)
  • 在 perimeter 的 setter 中,新值的名字是 newValue 。你可以在 set 之后显式的设置一个名字。

  • 注意 EquilateralTriangle 类的构造器执行了三步:

    • 设置子类声明的属性值
    • 调用父类的构造器
    • 改变父类定义的属性值。其他的工作比如调用方法、getters 和 setters 也可以在这个阶段完成。
  • 如果你不需要计算属性,但是仍然需要在设置一个新值之前或者之后运行代码,使用 willSet 和 didSet 。
  1. class TriangleAndSquare {
  2. var triangle: EquilateralTriangle {
  3. willSet {
  4. square.sideLength = newValue.sideLength
  5. }
  6. }
  7. var square: Square {
  8. willSet {
  9. triangle.sideLength = newValue.sideLength
  10. }
  11. }
  12. init(size: Double, name: String) {
  13. square = Square(sideLength: size, name: name)
  14. triangle = EquilateralTriangle(sideLength: size, name: name)
  15. }
  16. }
  17. var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
  18. print(triangleAndSquare.square.sideLength)
  19. print(triangleAndSquare.triangle.sideLength)
  20. triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
  21. print(triangleAndSquare.triangle.sideLength)

3. 处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加?。如果?之前的值是nil?后面的东西都会被忽略,并且整个表达式返回nil。否则,?之后的东西都会被运行。在这两种情况下,整个表达式的值也是一个可选值。

  1. let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")//如果这里赋值为nil,并且下一语句中没有`?`,则会出错
  2. let sideLength = optionalSquare?.sideLength

枚举和结构体

  • 使用rawValue属性来访问一个枚举成员的原始值。
  • 也可以使用字符串或者浮点数作为枚举的原始值。
  • 使用 init?(rawValue:) 初始化构造器在原始值和枚举值之间进行转换。
  1. if let convertedRank = Rank(rawValue: 3) {
  2. let threeDescription = convertedRank.simpleDescription()
  3. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注