【Swift官方助读】重点摘取

Swift概览

1 基本的字符串操作 输入输出在swift中无需引入库文件

2 在全局写代码作为程序的入口,因而无需main()函数也无需在每句statement后加分号

3 "this is my number" + String(appleNum) 字符串中插入字符串 方法用+号及强转字符串

4 "this is my number (appleNum + orangeNum)" 在字符串中引用别的类型时可以这样的形式

5 数组字典

var shoppingList = ["1", "2", "3"]
var shoppingList1 = [String]()
var shoppingList2 = []; //官方并未举这个例子创建数组 但该方法用于一次性置空已存在的数组
shoppingList[1] = "4"
shoppingList = []

var diction = ["location":"Beijing", "weather":"Cloudy", "transport":"Good"]
var diction1 = [NSString: NSString]()
var diction2 = [:] //同样不是官方推荐初始化方法 但该方法用于一次性置空已存在的字典
diction["population"] = "50000"
diction = [:]

6 if 语句必须是Bool判断表达式 而不会默认拿一个值与0进行比较了 所以要想截获单纯值可能失败的情况则需要引入optional值了 var optionalString: String? = "Hello" , print(optionalString == nil) 来比较要么用if let name = optionalName {}来判断 并得到解绑的值给name

7 (optionalNickName ?? noneOptionalDefaultName) 这个??符号表示如果前面的可选值为nil那么久直接返回后面的非可选值

8 switch支持任意对象 和 更多的比较操作而不仅仅是integer的相等操作 且不再需要break来标注结束该case默认成功就不会往下执行

let fullName: String = "John Appleseed"
switch fullName {
case "John":
    print("yes here")
case "John Appleseed", "JUST":
    print("Hi it's me")
case let x where x.hasSuffix("pepper"):
    print("pepper now")
default:
    print("None")
}

9 for in 函数可以直接遍历字典数据类型了 注意字典是无序的所以结果也是随机的顺序

let interestingNumbers = [
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
print(largest)

10 循环While 既可放在前面也可以放在后面 放在后面记得加上repeat 如果要循环也可以用上面的for in 注意:..< 不包含最右值 ...都包含左右值

//【0】
var n = 2
while n < 100 {
    n = n * 2
}
print(n)

//【1】
var m = 2
repeat {
    m = m * 2
} while m < 100
print(m)

//【2】
var total = 0
for i in 0..<4 {
    total += i
}
print(total)

11 func 方法 参数列表 与返回值的划分 用 -> 区分 前面是参数后面是返回值 参数和返回值的名在前类型在后

//调用时参数名为默认方法的参数名一致
func getMyName(withKey: String, day: String) -> String{
    return withKey + "is Friday \(day)"
}

getMyName(withKey: "Yes", day: "No")

//如果想隐藏或自定义可以加前下划线或者加多一个参数
func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")

//返回tuple多参数的返回值 返回值可以通过名称拿到也可通过索引获取
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    
    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }
    
    return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)

//除了可以有数组列表做参数 还可以用某一个类型的未知个数列表做参数
func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}
sumOf()
sumOf(numbers: 42, 597, 12)

//与上面的区别就是直接传数组 需要创建数组
func sumOfNumberWith(numbers: [Int]) ->Int{
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}

let array = [1, 2, 5]
sumOfNumberWith(numbers: array)

12 Function可以嵌套 在嵌套的方法中可以使用嵌套方法以外的方法内的变量 且方法是一等类型所以方法可以返回方法 也可以当做方法的传参

Function是一个特殊的块能被稍晚再调用,并能访问位于块被创建区域内的其它变量和方法
func lessThanTen(number: Int)-> Bool{
    return number < 10
}

func hasAnyMatches(list: [Int], condition: (Int) -> (Bool)) -> Bool {
    
    for item in list {
        if condition(item) {
            return true
        }
    }
    
    return false
}

func haseAnyMatches(list: Int..., condition: (Int) -> (Bool)) -> Bool{
    
    for item in list {
        return condition(item)
    }
    
    return false
}

let list = [20, 25, 31, 11, 20]
haseAnyMatches(list: 15, 19, 29, condition: lessThanTen)
hasAnyMatches(list: list, condition: lessThanTen)

//闭closure与方法作为参数调用的区别就是把整个方法体都写进来了
//如果这个块作为方法参数已经很明确了即可直接忽略参数类型和返回值 更精简
//也可以省略参数使用下标来获取 既然参数都没有了 那就直接省略了in这个区分参数和返回值的符号
let result1 = haseAnyMatches(list: 15, 19, 29, condition: lessThanTen)
let result2 = haseAnyMatches(list: 15, 19, 29, condition: {(number: Int) -> Bool in return number < 10})
let result3 = haseAnyMatches(list: 15, 19, 29, condition: {number in return number < 10})
let result4 = haseAnyMatches(list: 15, 19, 29, condition: {return $0 < 10})

result1
result2
result3
result4

13 代码规范

// 1 一个类型实现一个协议时建议单独声明一个扩展,保证逻辑性分离 如
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
}

// 2 代码分区 
// MARK: -

// 3 更多的使用LET,而不是VAR

// 4 不建议直接命名顶级变量,建议定义在结构体或者枚举内部,用static let 声明。 可以给这些变量一个合适的命名空间

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

radius * Math.pi * 2 // circumference 

// 5 对于一个可选类型var foo = Type? 不要使用强制解包
foo!.doSomethind()
使用可选绑定,或者可选链操作
if let foo = foo {
    // Use unwrapped `foo` value in here
} else {
    // If appropriate, handle the case where the optional is nil
}
foo?.callSomethingIfFooIsNotNil()

// 6 首选STRUCT而非CLASS 在非必需(比如没有生命周期)的时候使用struct,因为多态可以使用protocl实现 继承可以使用组合实现 值类型容易辨别,更可以用let去推测不可变的行为

// 7 只有在闭包或者命名冲突等必须时才使用SELF 忘掉Objective-C到底时使用self.pro 还是_ivar的访问方式,对于swift内部调用properties或者method省略掉self

// 8 对于只读的属性或者下标语法,使用隐式的GETTER方法
建议
var myGreatProperty: Int {
    return 4
}
subscript(index: Int) -> T {
    return objects[index]
}
不建议完整的写法,比较繁琐

var myGreatProperty: Int {
get {
    return 4
}
}
subscript(index: Int) -> T {
    get {
        return objects[index]
    }
}

14 类和对象

初始化用init
对象销毁前清理deinit

class Shape {
    
    var numberOfSides: Int = 0
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func simpleDescription() -> String {
        return "Shape with \(numberOfSides) sides"
    }
}

let shape = Shape(name: "Triangle")
shape.numberOfSides = 3
let descriptionStr = shape.simpleDescription()
descriptionStr

class Square: Shape {
    
    var sideLength: Double
    
    init(sideLength: Double, name: String) {
        
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }
    
    func area() -> Double {
       return sideLength * sideLength
    }
    
    var perimeter: Double {
        
        get {
        
            return 3.0 * sideLength
        }
        
        set {
            
            sideLength = newValue / 3.0
        }
        
        //不能同时和get或者set同时存在
//        willSet {
//            
//            sideLength = newValue * 3.0
//        }
//        
//        didSet {
//        
//        }
    }
    
    
    override func simpleDescription() -> String {
        return "square sides with sides of \(sideLength)"
    }
}

let squareInstance = Square(sideLength: 20, name: "FourSquares")
squareInstance.area()
squareInstance.simpleDescription()
squareInstance.perimeter
squareInstance.perimeter = 9
squareInstance.perimeter

15 Enumerations

默认是从0开始 自动按顺序增加1 但你可以通过给其赋不一样的值如浮点型或字符串赖改变这一默认行为 rawValue是对应的case的你所指定的值如果不指定 默认是Int类型就会自动以你指定的最后那一个后面开始加1 

另外虽然case只有三个 但每个case中如果有多个选项且是Int类型则还是依然会自动增加的只是这几种情况都做同一种case的处理而已 后面取值时同一个case下的三种情况对应三种取值

case时不要再认为case的值是rawValue的一个体现就像其他语言中是int的一个别名而已代表实际的int值 因为如果非必要rawValue有意义甚至可以不用设置rawValue 因而这个case所对应的值其实就是实际的枚举值 且这个rawValue必须要enum的type是确定的 不然是无法设置获取这个值得

enum Rank: Int {
    
    case ace = 1
    case two = 3, three = 5, four
    case five, six, seven
    
    //写成 .clubs因为知道这个常量就是枚举型的
    func simpleDescription() -> String {
        switch self {
        case .ace:
            return "ace123"
        case .two, .three, .four:
            return "two_three_four"
        default:
            return String(rawValue)
        }
    }
}

//第一种初始化 不能写成 .clubs因为还不知道这个常量是什么类型的
let rankOne = Rank.five
let rankOne: Rank = .five //或者这样也是可以的 因为知道类型
rankOne.simpleDescription()
rankOne.rawValue

//第二种初始化方法
let rankTwo = Rank(rawValue: 4)
rankTwo?.rawValue

//rawValue只有在有type类型时才会有且与初始化时的值一致
enum Suit: String {
    case spades, hearts, diamonds, clubs
}

let suitOne = Suit.diamonds
suitOne.rawValue

let suitTwo = Suit(rawValue: "hearts")
suitTwo?.rawValue

//enum的rawValue都是一样的 关联值可以每次创建时不一样
enum ServerResponse {
    
    case result(String, String)
    case failure(String)
}

let success = ServerResponse.result("6:00 am", "8:09 pm")

//拥有关联值得enum在switch时也会有所不同
//另外也可单独截取关联值出来 比如在switch中用let
switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
    print("Failure...  \(message)")
}

16 Structures

结构体和类非常类似 只是前者是值传递 后者是引用的传递
struct Card {
    
    var rank: Rank
    var suit: Suit
    
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}

17 Protocol

protocol ExampleProtocol{
    
    var simpleDescription: String {get}
    mutating func adjust()
}

class SimpleClass: ExampleProtocol {
    
    //实现协议需要的属性和方法 不然报错
    var simpleDescription: String = "SimpleDescription"
    var simpleOtherProperty: String = "OtherProperty"
    
    func adjust() {
        simpleDescription = simpleDescription + "_____"
    }
}

//因为是值类型 需要显示写上mutating才能修改结构体自身的属性值 class不需要因为class本身可以修改自身
struct SimpleStruct: ExampleProtocol{
    
    var simpleDescription: String = "SimleStruct"
    
    mutating func adjust() {
        simpleDescription = simpleDescription + "******"
    }
}

var a = SimpleClass()
a.adjust()
a.simpleDescription

var b = SimpleStruct()
b.adjust()
b.simpleDescription

18 Extension

extension Int: ExampleProtocol {
    
    var simpleDescription: String {
        return "Description__"
    }
    
   mutating func adjust() {
        self += 4
    }
}

7.simpleDescription

var digit: Int = 8
digit.adjust()
digit

let valueOfProtocol: ExampleProtocol = a
valueOfProtocol.simpleDescription
valueOfProtocol.simpleOtherProperty //找不到这个属性 类型是协议所以能拿到的东西仅限于协议内的而哪怕赋值了一个遵循了协议的对象 但也是拿不到那个对象的协议外的东西了

19 ErrorHandle

//系统的协议ErrorProtocol
enum PrintError: ErrorProtocol {
    
    case outOfPager
    case noToner
    case onFire
}

//方法参数后写上throws标记这个方法有抛出异常功能 然后在需要抛出异常的地方写上throw
func send(job: Int, toPrinter printerName: String) throws -> String {
    
    if printerName == "NeverHasToner" {
        throw PrintError.noToner
    }
    
    return "JobSuccess"
}

//关于捕捉错误
//try可以不需要返回值 也可以接受返回值 catch在失败的时候才会走且do里面try失败后的都不会再走了 catch里的error是系统返回的错误码变量
do {
    try send(job: 8080, toPrinter: "NeverHasToner")
} catch {
    print(error)
}

do {
    
   let result = try send(job: 8080, toPrinter: "NeverHasToneroooooo")
   print(result)
   let result1 = try send(job: 8080, toPrinter: "NeverHasToner")
   print(result1)
    
} catch {
   print(error)
}

//也可以像switch通过case来检验捕捉到的错误的具体case
do {
    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    print(printerResponse)
} catch PrintError.onFire {
    print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrintError {
    print("Printer error: \(printerError).")
} catch {
    print(error)
}

//或者也可以通过try?获取抛出异常的结果是否为nil
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")

20 defer 作用是在方法返回返回值前方法的所有其它代码执行后才执行这一段 所以可以做一些清理的工作

var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]

func fridgeContains(_ food: String) -> Bool {
    fridgeIsOpen = true
    defer {
        fridgeIsOpen = false
    }
    
    let result = fridgeContent.contains(food)
    return result
}
fridgeContains("banana")
print(fridgeIsOpen)

21 Generics

enum OptionalValue {
    case none
    case some(Wrapped)
}
var possibleInteger: OptionalValue = .none
possibleInteger = .some(100)

func anyCommonElements(_ lhs: T, _ rhs: U) -> Bool {
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
    return false
}
anyCommonElements([1, 2, 3], [3])

// is the same as writing 

22 第一章

1. 如果值不用改变永远优先使用常量胜过变量
2. 可以联排定义多个同类型的变量或常量 var red, green, blue: Double
3. 声明时如果有赋初始值则类型不需要写 因为类型推导是swift的一大特性
4. 支持这个命名哦 let  = "dogcow"  print() 
5. 当命名与系统冲突用重音符包围来区分 let `let` = "djfkdjfk";  print(`let`)
6. Double 至少 15 位小数位, Float 只有 6 位小数位. 如果有情形两者皆可时推荐用Double。Integer 书面表示可以为 binary  octal  decimal hexadecimal 四种。Floating-point 书面表示只能是 decimal 或 hexadecimal 小数点前后必须是这两种类型的数字。如果是 Decimal floats 可以可选的加上exponent,表示为大小写的 e 表示乘以10的多少次方; 但如果是 Hexadecimal floats 必须要加上exponent表示为大小写的 p表示乘以2的多少次方.
7. let justOverOneMillion = 1_000_000.000_000_1; let paddedDouble = 000123.456 都是用来增强易读性
8. UInt16(); String()转换类型
9. typealias AudioSample = UInt16 替换某个类型名称
10. Swift 提供两种表示 Boolean 值得写法 true 和 false: 且在if判断中必须是逻辑的Boolean值不是int那些非0
11. Tuple 类型 (Int, String) 例如: let tupleOne: (String, Int) = ("Sing", 4);  tupleOne.0;  tupleOne.1;  let (action, times) = tupleOne;  action;  times //可以被解赋值为命名或者索引来获取
12. Optionals 可选值类型 想要拿到可选值的值:1 与OC不同的是可以是所有类型不仅限于对象型 nil因此也就不再用于不是Optional类型的变量或常量。用了的话这个变量或常量就必须是可选型的。2 如果你确定即if与nil比较后 或者 一般在初始化时声明为强拆包型但需要有赋值(Implicitly Unwrapped Optionals) 即这两种情况下都能确定有值则可以强制拆包这个可选值(optionalValue!)来取值 或者 这时这个强拆包类型就可以被当做普通非可选型类型使用(但当做可选值类型也完全没问题)不用以后每次使用都拆包了 但你若不确定这个可选值是否一定有值强制拆包则会导致运行时错误。3 可选值绑定 if let value = optionalValue {} 
13. Assertions 是运行时的处理

23 第二章 操作符

1. let (x, y) = (1, 2); 如果是tuple元祖可以解析出变量或常量
2. if x = y {} 这种做法是错误的 在swift中等于赋值符号并无返回值 所以不能用来做bool的判断条件
3. + 可以用于字符串拼接中  另外+ - * / 默认不允许超限 如果需要处理可以使用 a &+ b的操作符
4. === and !== 用来检测两个对象引用是否指向同一个对象
5. Tuples如果有等同数量的值,且值本身都是可以比较的话 该tuples就也能比较 如两个(Int, String)就可以但若其中一个类型是Bool则不行. Tuples比较是从左到右,(1, "zebra") < (2, "apple")   // true because 1 is less than 2; (3, "apple") < (3, "bird")    // true because 3 is equal to 3, and "apple" is less than "bird"; (4, "dog") == (4, "dog")      // true because 4 is equal to 4, and "dog" is equal to "dog"; Tuples系统库支持最多6个元素,需要支持更多可以自定义实现其比较操作符
6. Nil-coalescing operator (a ?? b) 如果不为空解包一个可选值a否则就返回默认值b且b不能是可选值 相当于 a != nil ? a! : b

24 第三章 Strings and Characters

1. let valueOfStr = String(); let valueOfStrOne = ""
2. 声明为变量还是常量来决定字符串是否为可变 有点不同于OC的(NSString and NSMutableString)
3. String类型是值类型,系统会优化性能是否发生了真的拷贝,但对于使用者来说永远不用担心你对它的持有
4. let exclamationMark: Character = "!" Character类型
5. String创建还可以用一组Character来创建 let catCharacters: [Character] = ["C", "a", "t", "!", ""]; let catString = String(catCharacters)
6. 字符串可以用 + += 或者 append()来拼接,但注意不适用Character因为其必须只有一个character不能改变
7.  \(Double(multiplier) * 2.5) 字符串插入也可以运算
8.  String和Character 完全兼容Unicode标准
9.  Unicode scalar 就是Unicode背后的标准 let sparklingHeart = "\u{1F496}" // , Unicode scalar U+1F496
10.  注意Swift的Character values使用 extended grapheme clusters 意味着字符串拼接或修改并不始终会影响字符串的character的count属性 例如:如果你初始化一个包含4个字符的字符串"cafe" 然后拼接一个"\u{301}" 最后count不会变但字符串变为了café
11.  String Indices  获取index的内容 但超过后会有运行时错误 greeting[greeting.endIndex] // 运行时错误 for index in str.characters.indices { print("\(str[index]) ", terminator: "") }; 循环当前所有的index
12.  只要遵循Indexable protocol协议就可以使用 startIndex and endIndex 属性和相关的方法 index(before:), index(after:), and index(_:offsetBy:) 包括 String 和 collection types 比如 Array, Dictionary, and Set
13.  获取Unicode的String在存储编码时的utf8的码 for codeUnit in dogString.utf8 { print("\(codeUnit) ", terminator: "")}
14.  获取Unicode的String在存储编码时的unicodeScalars的码 for scalar in str.unicodeScalars { print("\(scalar) ")}

25 第四章 Collection Types

1. 有序Arrays, 无序sets, 无序and dictionaries 三种集合类型且能存储的值类型都是清晰的,因此你不用担心误插入了一个其他类型的值因此放心取改
2. 可不可修改就看你是否声明为变量和常量
3. 创建数组 var someInts = [Int]()  修改数组 shoppingList[4...6] = ["Bananas", "Apples"]; 
4. Set 是无序的且是里面的元素也是不同的的,数据必须要能Hashable 即自身有一个计算hashValue的方法 比如 a==b 则 a.hashValue = b.hashValue
5. Swift的所有基本型 (such as String, Int, Double, and Bool)默认都是Hashable可以存储在Set和当做字典的key,enumeration在没有关联值时也是默认hashable的. 如果是自定义的类型遵循一个继承自Equatable的Hashable协议后提供一个hashValue属性
6. 创建Set方法 var letters = Set(); var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]; var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"];注意可以用数组初始化Set,但为了区别所以必须显示的声明类型为Set
7. for item in shoppingList {print(item)}; 
   for (index, value) in shoppingList.enumerated() {print("Item \(index + 1): \(value)")}; 两种遍历Array效果 第二种遍历出index和值
8. for genre in favoriteGenres.sorted() {print("\(genre)")}; 遍历Set的有序输出
9. intersection(_:)  symmetricDifference  union  subtracting
10. Dictionary 与 [Key: Value] 两种形式 var namesOfIntegers = [Int: String]();  [:]; 比如这个var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"];
11. 

26 第五章 Control Flow

1. for _ in 1...power {answer *= base} 可以忽略遍历的值
2. repeat { } while 条件性的while
3. switch的每一个case都必须要写内容 而不能case好几个而统一在后面写内容 你可以在同一个case中逗号隔开好几个条件倒是可以 case "a", "A":
4. switch也可以case 1..<5: 
5. let somePoint = (1, 1)
switch somePoint {
case (0, 0):.................省略后面
6. let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):................省略后面
7. let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:.............省略后面
8. let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):........省略后面
9. OC的break(作用是终止判断或循环条件并跳出不往下执行)的替代品 那swift默认是不加也可以起到break的两个作用 这样一来就和OC相反的默认了 如果你想让switch继续执行下一个case且忽视下个case的判断条件的话就显式地加上fallthrough吧
10. labelName: while condition { statements }  给循环或判断加前缀 在使用break或者continue时就能正确的跳出
11. guard与else 成对出现  一定确保有值 guard let name = person["name"] else { return } 那如果为YES后面可以继续使用name这个constant 若为False则进入else 目的是不符合条件的话就尽早返回出去
12. if #available(iOS 9.0, *) { }else{ } 平台判断

27 第六章 Function

1. func sayHelloWorld() -> String{} 没有参数时也不能少了括号
2. func greet(person: String) {} 没有返回值的方法
3. func minMax(array: [Int]) -> (min: Int, max: Int) {} 多个返回值
4. func minMax(array: [Int]) -> (min: Int, max: Int)? {} 返回可选值
5. 默认参数名就是方法被调用的调用名 但每个参数其实还可以指定不一样的调用名 func someFunction(argumentLabel parameterName: Int) {};  argumentLabel就是调用名 忽略的话可以写_符号即调用时没有该参数名调用名
6. func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {} 可以有默认参数值 调用时就可以不需要传这个参数 设置了默认值得参数是无法被声明成inout类型的
7. func arithmeticMean(_ numbers: Double...) -> Double {}; 一个方法最多只能有一个数量可变参数variadic parameters 且可变数量参数类型是无法被声明成inout类型的
8. func swapTwoInts(_ a: inout Int, _ b: inout Int) {}; swapTwoInts(&someInt, &anotherInt);   inout参数类型在调用时必须传入的是var变量因为常量和字面量是无法改变的且带上符号&
9. func的类型是由参数类型和返回值类型决定的 一个方法可以说它是一个(无参数,返回Int型)的类型的方法  var mathFunction: (Int, Int) -> Int = addTwoInts;
10. func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {}; 传参可以以方法类型为参数类型
11. func chooseStepFunction(backward: Bool) -> (Int) -> Int {};  方法类型也可是返回值的类型 以最后一个箭头开始作为返回值即返回这个方法的类型
12. func chooseStepFunction(backward: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 }}; 内嵌方法可以在外围的大方法里被调用或作为大方法的返回值返回到另一个域中使用

28 第七章 Closure 闭包

1. 闭包包含三种:1 全局方法是有名字的闭包 2 内嵌方法是有名字且能从包围他们的大方法中捕获值的闭包 3 无名且可以从周围环境捕获值的方法
2. {(parameters) -> return type in statements } 闭包的格式 一般传递一个闭包作为方法或消息的参数时都可以从方法参数要求的类型中推断出参数返回值类型,所以就不用再闭包里显示的再写一次类型,可以省略
3. reversedNames = names.sorted(isOrderedBefore: { s1, s2 in s1 > s2 } ) 因为>在swift中是有返回值的 所以连return也可以省略
4. swift默认给闭包里的参数提供简洁的参数名 $0 $1 $2 且不需要再写in前面的参数列表了 让swift自动推断参数个数和类型 则只剩下body了因而直接省略in符号 reversedNames = names.sorted(isOrderedBefore: { $0 > $1 } )
5. 字符串定义了>为一个方法返回bool类型 reversedNames = names.sorted(isOrderedBefore: >)
6. trailing closure 当闭包作为最后一个参数时可以写到后面 reversedNames = names.sorted() { $0 > $1 }
7. trailing closure 当闭包作为唯一的参数时连括号都可以省略 reversedNames = names.sorted { $0 > $1 }
8. 即便声明该变量常量的域已经不存在了也能从周围的域中来捕获值 swift可能会基于优化将不可变值拷贝一份并管理因此带来的内存处理
9. 如果把闭包赋值给类实例的一个属性则会强引用这个类
10. 闭包是引用类型 所以闭包捕获的值和闭包赋值给多个常量其实都是指向同一个闭包 且赋值后的常量本身不能被改变 但闭包里面的值还是可以被改变的 互不影响
11. @noescape的用法  生命周期不能超过方法且声明的这个闭包也无法被强引用

func doIt(@noescape code: () -> ()) {

var i = 0

/* what we CAN */

// just call it
code()
// pass it to another function as another `@noescape` parameter
doItMore(code)
// capture it in another `@noescape` closure
doItMore {
    code()
    println(i) //且不需要写self
}

/* what we CANNOT do *****

// pass it as a non-`@noescape` parameter
dispatch_async(dispatch_get_main_queue(), code)
// store it
let _code:() -> () = code
// capture it in another non-`@noescape` closure
let __code = { code() }

*/
 }

 func doItMore(@noescape code: () -> ()) {}

12. @autoclosure 可以自动将表达式转为闭包形式即少了花括号,因为传的是可以被转为闭包的表达式是区别于一般的表达式的 不需要立马被执行,自动将这个表达式包装成闭包,这就是 @autoclosure 的作用啦. func serve(customer customerProvider: @autoclosure () -> String) { print("Now serving \(customerProvider())!")}; 
13. @autoclosure(escaping) 可以改变 @autoclosure默认为@noescape的事实 因为闭包在方法返回后要被调用 func collectCustomerProviders(_ customerProvider: @autoclosure(escaping) () -> String) {customerProviders.append(customerProvider) }; 

29 第八章 Enumerations

1. 如果给case设置了值 rawValue 则值的类型可以是字符 字符串 Int Float
2. associated values 则可以是任意类型 每个case也不一样
3. Enumerations还有类的很多功能,可计算属性来提供当前枚举值的更多信息,给枚举值提供实例方法,初始化器来提供初始值,可以被扩展,也可以实现协议
4. 如果没有指定具体类型 则每一个case就是一个完整的枚举名类型的值 即不是Int也不是其他 每个枚举都给swift定义了一个新的类型,在后面知道该类型后取其case可以直接用.符号
5. Associated Values 关联值 enum Barcode { case upc(Int, Int, Int, Int)  case qrCode(String)}
6. Associated Values 变量接受 switch productBarcode { case .upc(let numberSystem, let manufacturer, let product, let check):  这里可以用变量接受
7. Raw Values 默认值 类型必须是 strings, characters, or any of the integer or floating-point number types的一种,且每种case必须是唯一的赋值
8. Raw Values 每次创建都一样  Associated Values 每次可以不一样
9. 如果Raw Values是integer或者string , 如果integer自动加1默认为0, string则为case名
10. 如果给enum设置了Raw Values类型 则自动生成一个初始化器且返回一个可失败的初始化器failable,let possiblePlanet = Planet(rawValue: 7); 否则一般不设置类型就是要使用第一个为默认值比如:var directionToHead = CompassPoint.west
11. Recursive Enumerations 递归枚举 关联值为自身枚举enum enum 例如:ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

//也可以写在开头
indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}
//最终使用就像这样 let five = ArithmeticExpression.number(5) 

30 第九章 Classes and Structures

1. 类和结构体的共同点 1. 都可定义属性 2. 都能定义方法 3. 定义下标subscript 4. 初始化器 5. 扩展 6. 协议
2. 类比结构体多了 1. 继承后拥有父类的所有 2. 类的实例对象可以在运行时确定类型 3. Deinitializers使类的实例对象能释放资源 4. Reference counting类的实例对象可以被多个引用 而结构体则是copied 
3. 创建是一样的 struct Resolution { var width = 0; var height = 0} , class VideoMode { var resolution = Resolution() ,var interlaced = false}, 然后默认实例对象创建为并自动设置了默认值 let someResolution = Resolution();
4. 无论是类还是结构体属性访问都用点语法 与OC不同,可以用多个点语法直接访问属性的子属性 someVideoMode.resolution.width = 1280
5. structure结构体有一个自动的初始化器 Memberwise Initializers 例如可对其属性赋初值 let vga = Resolution(width: 640, height: 480) 类没有这样的
6. integers, floating-point numbers, Booleans, strings, arrays and dictionaries都是值类型即value types,背后都是由structures实现的 , 枚举enumeration和structure是值类型,值类型在赋值给常量 变量或方法时值类型 其值都是会被copy 也包含其里面的值类型属性,。这不同于OC的Foundation 的 NSString, NSArray, and NSDictionary是由class实现的,因而在传递中都是引用赋值而不是拷贝copy。系统对copy是有优化的只有真正需要的时候系统底层才会发生真实的拷贝
7. 类class是引用类型,在赋值给常量变量或方法时引用类型是不会copy的,而是指向的同一个实例对象。 swift中的指针指向也无需星号标记 let classInstatnceTwo = classInstance; 
8. ===  用来对比是否为同一个实例对象identical   == 为值是否相等equal
9. class为引用传递 structure为值传递 根据具体情况选择使用哪种类型 一般参考:1 structure主要的作用就是封装一些相关的数据值 2 structure实例对象希望在传递过程中都是拷贝而不是引用 3 structure实例对象里的所有属性在传递过程中都是拷贝而不是引用 4 无法继承别的结构体的属性或行为behavior 除开这四种情况其它的都适合用class,实践表明,自定义类型的都用class,系统值类型的则用结构体

31 第十章 Properties 属性

1. Properties 就是将值关联到class, structure, or enumeration.
2. Stored properties 储存常量或变量作为对象的一部分,而computed properties计算这个值. Computed properties由classes, structures, and enumerations提供,Stored properties仅仅由classes and structures提供.
3. type property 和 instance property 一个是实例的一个是类的
4. Property observers即 willSet didSet 可以直接加到自定义的Stored properties上(lazy property不行)或者从父类继承来的属性(包括继承的lazy 或 computed property属性,如果是继承来的则是在父类初始化完后该属性于子类被设置时才调用)后面一对括号接在属性正常的定义后面就行了。作为定义的一部分,Stored properties可以设置一个默认值,在初始化时依然可以给再次设置初始值即使是constant常量存储属性,当然常量的属性初始化后就不能再改变了。newValue 和 oldValue是系统默认的值可以直接用。如果一个inout属性传递给方法参数后这个inout属性的观察者就会一直被调用,因为属于copy-in copy-out memory model for in-out parameters,方法完成后值会被重新写回属性里。
5. 值类型的实例如果是常量则其所有属性都是常量 如structure 引用类型则不同即便是常量但依然可以改变属性 如class
6. lazy stored property的初始值直到第一次使用才计算好 因而必须要设置成var变量,常量必须在initialization完成之前设置好,因而无法设置constant为懒加载属性。懒加载时在多线程同时访问时swift并不能确保这个属性只被初始化一次。
7. computed properties 由 classes, structures, and enumerations提供,该类属性并不存储值而是有一个getter和setter来获取及设置其它属性或值的功能。包括只读的computed properties也必须都定义为变量因为他们的值并不固定。只读的计算型属性就去掉set就行了,为了简写方便也可以去掉get直接return值出去。var center: Point { 
          get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY) }    
          set(newCenter) { //另外还有一个newValue是系统默认的设置新值 因而可以直接用来替换newCenter 省去了括号里就不用定义这个newCenter了
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2) } }
8. Global variables 定义在 function, method, closure, or type context以外的. Local variables 定义在 function, method, or closure context内的.Stored variables与stored properties一样,Computed variables 与 computed properties一样. 你可以定义 computed variables 或者定义 observers 给stored variables, 不管是global 还是 local scope. 全局的常变量总是computed lazily且不用标记为lazy,而局部的常变量则永不computed lazily。
9. Type properties是一个类型共有的,而不是对象相关。Stored type properties 可以是variables or constants. 但Computed type properties常常是 variable properties与computed instance properties一样。stored type properties 必须要有一个初始值。Stored type properties 是懒加载的且保证在多线程中只被初始化一次且无需lazy关键字定义。 Type properties 都可以用 static 声明.  class的computed type properties, 用 class 声明允许 subclasses 重写 superclass’s 实现。enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}
10. 

32 第十一章 Methods 消息方法

1. Methods 就是与特定类型相关连的 functions, 可分实例方法和类方法.Classes, structures, and enumerations都可以定义方法
2. self property 在自己的实例方法内指当前实例对象,在类方法里指类本身。一般都是默认不用特定声明self。但如果方法参数名和属性相同时则需要self来特指属性 并与参数名区分开 
3. Structures and enumerations 是 value types. 默认来说value type的properties (甚至self也可以被修改,即这个新实例对象就会替换已存在的)无法在它的instance methods中被修改,如果需要修改就在方法前加一个 mutating 关键字,另外structure这些value type的要想在外部修改其内部属性哪怕是变量属性都需要声明称实例变量不要常量哦。
4. 方法前加static就变成了type methods. 类Class可以用class关键字声明在func前允许subclasses可以重写superclass’s implementation of that method.类方法可以互相访问,类属性也可以互相访问

33 第十二章 Subscripts 下标

1. Classes, structures, and enumerations 可以定义 subscripts,这是一种访问collection, list, 或 sequence里的成员的捷径,避免每个元素的设置获取都需要写一个设置获取方法来执行。
2. 单个类型可定义多个 subscripts根据index的类型来选择适合的subscript 而且 subscripts 可以有多个参数
3. 以subscript开头和参数返回值拼接可多参数,参数返回值类型均可任意(除了in-out 外且参数不能有默认值 default parameter values.),结构与computed properties类似,有get和set组成(当然也可以是只读即只有get)。subscript(index: Int) -> Int {
    get {
        // return an appropriate subscript value here
    }
    set(newValue) {
        // perform a suitable setting action here
        //如果这里不指定newValue也是可以自动系统生成 类似computed properties一样,且这个newValue类型与返回值一致。
    }
}
4. subscript overloading的意思是class or structure 可以提供多个 subscript.     例如:subscript(row: Int, column: Int) -> Double {
        get {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValid(row: row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }

34 第十三章 Inheritance 继承

1. 类可以从别的类继承 methods, properties, and other characteristics
2. 子类中可以给父类的属性添加Property observers 不管它原本定义的是 stored or computed property.因为子类只知道父类有这个属性的名称和类型并不知道原来是什么。但你不可以添加 property observers 给继承的 constant stored properties 或者只读的 read-only computed properties. 因为他们无法被set,也就无法被观察了。另外也不可对同一个属性同时既重写又加观察者,你可以在重写时就做了这个功能。
3. 不指定superclass 自动成为基类 base classes。子类可提供对继承来的 instance method, type method, instance property, type property, or subscript 自己的实现,重写overriding.所以在前面需要加上override关键字,不加就会作为error报错。访问父类的方法属性下标要加上super,如super[someIndex];
4. 你可以重写父类的只读属性为读写属性 read-only property as a read-write property 反之则不可。如果你重写了属性的setter但必须也要重写getter(没有意愿修改getter返回值则可直接返回系统的属性)。
5. 使用final来防止method, property, or subscript被子类重写.例如 (such as final var, final func, final class func, and final subscript). 视图重写final的会在运行时报错。final也适用于extension的class添加中。当然将一整个final class定义时整个类就不允许有子类。

35 第十四章 Initialization 初始化

1. 初始化 class, structure, or enumeration 用来使用的过程,包括必须给每一个stored property存储属性的赋值及初始化前的一些设置。swift的初始化器没有返回值。只有class才有的deinitializer用于该实例dealloc前的清理。注意在initializer中设置是不会调用任何属性的观察者observer的 格式为init() {}, 赋初值可以是定义时给默认值或者在init中设置值,能给默认值的优先。
2. 初始化器的过程可以是 1 消息参数 可选属性类型 在initializer中指定常量属性 
3. 因为initializer和普通的方法不一样 他没有方法名,所以只能靠参数和argument label,来区别哪一个初始化方法被调用。swift自动给初始化器中的每一个参数提供了argument label,如果故意不写argument label直接传一些值则会报错。但可以显示的加上下划线于参数前则可以不写argument label调用直接传参数。比如:init(_ celsius: Double) { temperatureInCelsius = celsius }。如果初始化时有属性可能未来为空值或者在initializer中无法设置初始值,则可以将属性设置为可选类型。如果是Constant Properties,则初始化后不可以再次修改值了,但class中Constant Properties可以仅在父类的initialization的过程中被修改子类无法修改,
4. Default Initializers 是给任何 structure or class 的属性设置了default values并没有initializer的,而Default Initializers只是简单地创建了一个所有属性都有默认值的实例.对于structure来说还有一这种方法叫Memberwise Initializers,即没有初始化器,但区别类的是即便有属性没有默认值也可以有这个Initializers。
5. initializer delegation就是initializer调用其它的initializer,值类型和引用类型略有不同。Value types (structures and enumerations) 不支持继承所以只能调用自身提供的其它initializer相对简单. Classe可以继承意味着要一起确保所有的stored properties在initialization期间有赋值。如果是值类型用自定义initialization可以用self.init来调用同一个值类型的其它initialization,也就没有默认的初始化器了,所以想好了或许你可以写到扩展里这样就都能用了而不是写在原本中或者把系统默认的两种(1 每个属性为argument label调用名 2 自动)自己写上去。
6. class所有的stored properties都必须在initializer要有初值,designated initializers 和 convenience initializers两种,前者是主要的后者辅助,因为它可以完全初始化这个类的所有属性并调用父类的初始化,一般只有也必须要有一个designated。initializers,如果不需要可以不创建Convenience initializers因为它只能调用同一个类的其它初始化器,且最终还是要调用designated的,designated的只能调用其最接近的父类的designated。 格式:convenience init(parameters) {};所以Designated initializers 必须往上调Convenience initializers必须平级调用。
7. 初始化两个阶段: 【第一阶段】给由该类定义的每个stored property被赋初值(OC中的就无法自定义初始化值, Objective-C assigns zero or null values (such as 0 or nil) to every property.) 过程为:class调用designated or convenience initializer,实例的内存已申请创建但未被初始化,接着designated initializer确认所有本类中定义的stored properties都有值,这些属性的内存随即被初始化了。接着调用父类的初始化器执行上面的步骤直到最顶层。一旦到了顶层确保所有的stored properties都有值了,实例的内存就算完全初始化了。 【第二阶段】是每个类有机会可以自定义它的属性stored properties。 过程为:至上而下每一个designated initializer都可以自定义实例,然后在初始化器中也可以访问self,修改属性,访问实例方法,最后任意convenience initializers也可以自定义实例了也可以访问self了。  swift安全监测4步骤:1 调用父类的初始化前保证该类定义的所有属性都有初始值 2 赋值给继承父类的属性前必须自身的Designated initializers调用了父类的初始化器不然会被父类覆盖 3 给属性赋值前convenience initializer必须调用了其它初始化器不然可能被本类其它初始化器覆盖 4 第一阶段完成以前initializer中不能访问实例方法 读取属性或指向self。
8. Initializer Inheritance and Overriding , 子类默认不继承父类的初始化器防止未完全初始化,如果又不想丢失父类的那些初始化方法就自己重写父类的吧。如果你自定义的和父类的designated initializer或default initializer时就要加override,哪怕在子类中是一个convenience initializer重写了父类的designated initializer也要记得加上override。但如果重写的是父类的convenience initializer,因为无法纵向调用则无需override也不会真正意义上重写父类的convenience initializer。子类可在初始化器中修改继承来的可变属性 variable properties但继承来的常量属性不可修改
9. 自动继承父类初始化器情况,1 如果子类没有任何designated initializers则自动继承父类的designated initializers 2 如果子类提供了所有父类的designated initializers实现通过方式1或者重写则自动继承父类的convenience initializers。 这两条规则适用于添加convenience initializers
10. Failable Initializers 适用于初始化时必须要满足某种条件,可以有一个或多个这样的初始化器,只需要加上init?标记,一个初始化器不可能既是普通的又是可失败的。普通的没有返回值,但这种初始化器在失败的情况下需要返回一个nil,成功则不用管。
11. Failable Initializers for Enumerations enum 
    
    TemperatureUnit {
    case kelvin, celsius, fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .kelvin
        case "C":
            self = .celsius
        case "F":
            self = .fahrenheit
        default:
            return nil
        }
    }
}
12. Failable Initializers for Enumerations with Raw Values 自动有一个可失败的初始化器 init?(rawValue:)
13. Propagation of Initialization Failure 同类中可相互调用,子类可调用父类的。可失败初始化器能调用父类的不可失败初始化器。子类可重写父类的failable initializer,甚至可以将其重写成nonfailable initializer,但反之不可。
14. init!方法是可失败的初始化器的另一种,只是后者返回一个可选值,而前者返回一个implicitly unwrapped optional instance。可以从init? 调用 init! 或相反 也可以重写 init? with init! 或相反 ,也可以 init to init!, 尽管会触发 assertion 如 init! initializer引起的initialization 失败
15. required 加在前面表示每一个子类必须实现该 initializer, 如果重写父类的required初始化器则不需要写override而必须写required替代,防止后续还有subclass
16. 使用closure赋值给属性 注意里面是return 且closure后面带了一对括号表示立马执行 少了括号就成了赋值一个closure给属性了 另外在这个closure里面不能访问self或者实例方法或其他属性哪怕有默认值因为现在还没有完成initialization 但如果是lazy属性则可以使用self因为这时已存在 
    class SomeClass {
    let someProperty: SomeType = {
        // create a default value for someProperty inside this closure
        // someValue must be of the same type as SomeType
        return someValue
    }()
} 

36 第十五章 Deinitialization 清理

1. deinit 只有class才有 在dealloc一个类前调用。自定义的类在释放前需要清楚自定义的相关信息 deinit { // perform the deinitialization }。 deinit只能有一个,是被自动调用的。且可以访问所有属性方法,

37 第十六章 ARC

1. 当把class实例赋值给一个 property, constant, or variable, 这个被赋值的 property, constant, or variable 就对这个实例持有强引用了.直到这个引用不用了才会被释放
2. Weak 和 unowned references 使循环引用中一个实例不强持有彼此,这个实例然后就可以不相互引用且又互相指向,前者可能在后面为nil后者不能为nil直到生命周期结束
3. Property observers 不会被调用当ARC设置一个 weak reference 为 nil.
4. 还有一种情况是两个属性都不能为nil 比如国家和首都的关系, 这个时候需要结合 一个类属性为an unowned property 与 一个类属性为an implicitly unwrapped optional property,这可以保证两边的属性都可以访问但却又不是强引用因为一边是可选值只不过这个可选值是必须保证使用时存在的。
5. Strong Reference Cycles for Closures里的强循环引用,closure capture list来解决。尽管在 closure 中不止一次指向 self 但仍只强引一次self,且在closure中推荐使用self与相关的属性方法已提醒引用。列表写在in的最前面
   lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    // closure body goes here
}
  lazy var someClosure: () -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here
}

6. unowned 当 closure 和 the instance it captures will always refer to each other, and will always be deallocated at the same time. 相反, define a capture as a weak reference when the captured reference may become nil at some point in the future. Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated。If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference.

37 第十七章 Optional Chaining

1. 在查询或调用可选值类型的 properties, methods, and subscripts时有可能出现nil时的一种写法.使得可以连续访问直到某一个为nil时整个chain就返回nil了,multi时返回的永远只有一个可选值不会因为已经是可选值返回就more可选值,也不会因为不是可选值返回就不是可选值。有点类似发送nil,但适用于任何类型。 optional chaining 返回的结果与期望返回值类型一致,只是封装在了一个可选值中,比如当通过optional chaining访问一个Int型的属性将返回成Int?
2. 调用方法返回的也是可选值 记得如果方法返回非可选值但整个可选链还是会返回可选值 如果方法后面还要继续调用属性比如返回一个字符串再接着调用长度就需要在方法调用后打上问号表示可选了 john.residence?.printNumberOfRooms()?.length
   if john.residence?.printNumberOfRooms() != nil {
    print("It was possible to print the number of rooms.")
  }
3. 通过可选链设置属性也是返回的可选值
  if (john.residence?.address = someAddress) != nil {
    print("It was possible to set the address.")
  }
4. subscript时注意问号写在最直接可能为nil的变量后边  比如设置 john.residence?[0] = Room(name: "Bathroom") 或者获取
  if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
 }
5. 读取字典key var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]; testScores["Dave"]?[0] = 91

38 第十八章 Error Handling

1. Swift 提供 first-class 支持给 throwing, catching, propagating, 和 manipulating recoverable errors at runtime.
2. Representing and Throwing Errors 在Swift中 errors 是以遵循了Error protocol的类型展示出的,这个空协议暗示该类可以用来处理错误。比如:
   enum VendingMachineError: Error {
     case invalidSelection
     case insufficientFunds(coinsNeeded: Int)
     case outOfStock
  }  如果需要抛出错误则用 throw ,例如: throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
3. Handling Errors 在swift中并不包括高计算性能的 unwind call statck, 而是性能特征跟return语句差不多。 有四种方法 1 propagate the error from a function to the code that calls that function, 2 using a do-catch statement, 3 handle the error as an optional value, 4 assert that the error will not occur
4. 调用支持抛错的方法必须也要在调用该方法时标记来表明处理错误,在其前加上 try 继续抛错 或者用 try? or try!, 用在方法前
5. throwing function抛异常方法写 throws 在方法名参数后返回之前 func canThrowErrors() throws -> String ;  func cannotThrowErrors() -> String;
6. A throwing function 可以将抛错从方法内转移至该方法被调用的域,注意只有throwing functions 可以转移 errors.任何在nonthrowing function里被抛出来的 errors 必须在nonthrowing function内被处理
7. func vend(itemNamed name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.invalidSelection
        }
   }
8. 带throws的方法可以传递任何内部抛错因而任何调用该方法的都必须要么处理错误(a do-catch statement, try?, or try!)要么继续转移错误。
  struct PurchasedSnack {
    let name: String
    init(name: String, vendingMachine: VendingMachine) throws {
        try vendingMachine.vend(itemNamed: name)
        self.name = name
     }
  }
9. do-catch 用来处理 errors ,如果在do中被抛出了错误然后在catch中可找到可处理的抛错。 catch后可以有自定义的具体错误格式,如果没写则默认绑定一个名为error的本地常量
   var vendingMachine = VendingMachine()
   vendingMachine.coinsDeposited = 8
     do {
       try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    } catch VendingMachineError.invalidSelection {
       print("Invalid Selection.")
   } catch VendingMachineError.outOfStock {
       print("Out of Stock.")
   } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
      print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
  }
10. 使用 try? 处理抛错 error by converting it to an optional value. If an error is thrown while evaluating the try? expression, the value of the expression is nil. 
11. throwing function 实际运行中并不会抛错,这种情况可以写 try! 禁止再传播抛错。但如果运行时却又错误出现则会报运行时错误。.let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")图片从程序中获取因而可以保证获取到所以不需要再传播抛错
12. defer在代码块结束前执行一系列的操作可做一些必要的清理无论是因为抛错还是return break。 
    func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // Work with the file.
        }
        // close(file) is called here, at the end of the scope.
    }
  }

39 第十九章 Type Casting

1. Type casting 是一种检测实例类型或者在自身的继承关系中被对待为别的类型的父类或子类。有is和as可选。is判断为某特定的子类。一个某类型的 constant 或 variable 可能实际指向一个子类的实例,因此可以尝试用as,as?(返回可选值),as!(将可选值直接解包)来downcast。downcast操作一般见于for循环但也可以直接对一个数组全盘进行downcast啊。
2. AnyObject代表一个任何class类型的实例。Any代表任何类型的实例,包括方法function类型哦.
3. var things = [Any](); things.append(0); things.append(0.0); things.append("hello"); things.append((3.0, 5.0)); things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman")); things.append({ (name: String) -> String in "Hello, \(name)" });

40 第二十章 Nested Types

1. 就是嵌套

40 第二十一章 Extensions

1. Extensions 添加新的方法给已存在的 class, structure, enumeration, 或 protocol 类型。与OC的categories类似但没有名称。作用:1 添加实例或类的computed属性 2 定义实例或类方法 3 定义subscripts 4 新的初始化方法 5 遵循协议 6 定义使用新的嵌套类型
2. Extensions 可以添加新的方法但是却无法重写已存在方法
3. extension SomeType {
    // new functionality to add to SomeType goes here
}
extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}
4. 如果给已存在的类定了extension来添加新方法,这些新方法会存在于即便是extension定义前已存在的实例上。
5. extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
6. Extensions可添加新的 computed properties, 但无法添加 stored properties, 或 property observers给已存在属性。
7. Extensions 可给class添加新的 convenience initializers ,但无法给class添加 designated initializers 或 deinitializers. Designated initializers 和 deinitializers 必须被original class 实现.
8. 如果使用 extension 给一个value type(所有stored properties已有默认值且无任何自定义初始化器)添加 initializer,你可在extension’s initializer中调用默认初始化器和 memberwise initializer.但如果在原实现中已写了初始化器则不能这样了。
9. 提供新的 initializer with an extension, 人需要确保每个实例在初始方法结束时都被完全初始化。
10. 扩展中添加的实例方法也可以修改实例本身,Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation.

41 第二十二章 Protocols

1. Protocol 可以被class, structure, or enumeration 遵循来实现协议的要求
2. class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {}; 注意协议要放到类型的后面
3. A protocol can 要求 any conforming type to provide an instance property or type property with a particular name and type. 并不要求 whether the property should be a stored property or a computed property — 只是指定 required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable.If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for the property to be also settable if this is useful for your own code.
4. protocol FullyNamed {
    var fullName: String { get }
}
5. protocol AnotherProtocol {
    static var someTypeProperty: Int { get set }
}
6. 如果在遵循了协议后不实现协议所要求的就会运行时报错
7. protocol SomeProtocol {
    static func someTypeMethod()
}
protocol RandomNumberGenerator {
    func random() -> Double
}
8. 协议规定方法不需要写末尾的一对括号,方法支持 Variadic parameters. 但是 Default values不可以在协议定义中指定给方法参数
9. 如果你定义一个protocol的 instance method 要 mutate instances of any type that adopts the protocol, 写上 mutating keyword as part of the protocol’s definition. 使 structures and enumerations 。你不需要 write the mutating keyword when writing an implementation of that method for a class. The mutating keyword 仅适用于 structures and enumerations.
10. protocol SomeProtocol {
    init(someParameter: Int)
}
11. 你可以在class上以designated initializer or a convenience initializer方式实现协议的初始化器,不管哪种都必须要在实现中标上 required
    class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // initializer implementation goes here
    }
}
12. 不需要加required当class是final 因为不可能有子类了。
13. 如果子类重写父类的 designated initializer 并同时也正是protocol的初始化器,因而必须 required and override 关键字。
   protocol SomeProtocol {
    init()
}
 
class SomeSuperClass {
    init() {
        // initializer implementation goes here
    }
}
 
class SomeSubClass: SomeSuperClass, SomeProtocol {
    // "required" from SomeProtocol conformance; "override" from SomeSuperClass
    required override init() {
        // initializer implementation goes here
    }
}
14. A failable initializer requirement can be satisfied by a failable or nonfailable initializer on a conforming type. A nonfailable initializer requirement can be satisfied by a nonfailable initializer or an implicitly unwrapped failable initializer.
15. Protocol可以看做一个完全的类型,代理 Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type。
class Dice {
    let sides: Int
    let generator: RandomNumberGenerator
    init(sides: Int, generator: RandomNumberGenerator) {
        self.sides = sides
        self.generator = generator
    }
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }
}
16. 代理
protocol DiceGame {
    var dice: Dice { get }
    func play()
}
protocol DiceGameDelegate {
    func gameDidStart(_ game: DiceGame)
    func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
    func gameDidEnd(_ game: DiceGame)
}

17. You can extend an existing type to adopt and conform to a new protocol, even if you do not have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension.
18. If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension:
struct Hamster {
    var name: String
    
    //这个方法是TextRepresentable协议的
    var textualDescription: String {
        return "A hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {}

Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol.

19. A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits.
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // protocol definition goes here
}

20. You can limit protocol adoption to class types (and not structures or enumerations) by adding the class keyword to a protocol’s inheritance list.
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

21. It can be useful to require a type to conform to multiple protocols at once
protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
    print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)

22. You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type:

23. You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the optional modifier as part of the protocol’s definition. Optional requirements are available so that you can write code that interoperates with Objective-C. 
Both the protocol and the optional requirement must be marked with the @objc attribute. Note that @objc protocols can be adopted only by classes that inherit from Objective-C classes or other @objc classes. They can’t be adopted by structures or enumerations.
When you use a method or property in an optional requirement, its type automatically becomes an optional. For example, a method of type (Int) -> String becomes ((Int) -> String)?. 
Note that the entire function type is wrapped in the optional, not the method’s return value.

@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}

class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.increment?(forCount: count) {
            count += amount
        } else if let amount = dataSource?.fixedIncrement {
            count += amount
        }
    }
}

24. Providing Default Implementations
You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol. 
If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.
Protocol requirements with default implementations provided by extensions are distinct from optional protocol requirements. Although conforming types don’t have to provide their own implementation of either, requirements with default implementations can be called without optional chaining.

//旧协议扩展定义了一个新属性 默认返回了旧协议的属性值
extension PrettyTextRepresentable  {
    var prettyTextualDescription: String {
        return textualDescription
    }
}

25. Adding Constraints to Protocol Extensions
When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a generic where clause

extension Collection where Iterator.Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}

42 第二十三章 Generics

1. func swapTwoValues(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}
//both a and b must be of the same type T, whatever T represents
Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ).

2. Naming Type Parameters
 Dictionary and Element in Array, which tells the reader about the relationship between the type parameter and the generic type or function it’s used in. However, when there isn’t a meaningful relationship between them, it’s traditional to name them using single letters such as T, U, and V
 
3. Generic Types
In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary.

//Element 不再是单独的 Int Double等类型
struct Stack {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

4. Extending a Generic Type
5. Type Constraints
Ex: This requirement is enforced by a type constraint on the key type for Dictionary, which specifies that the key type must conform to the Hashable protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default.

func someFunction(someT: T, someU: U) {
    // function body goes here
}

6. Associated Types

protocol Container {
    associatedtype ItemType
    mutating func append(_ item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

7. Generic Where Clauses
You write a generic where clause right before the opening curly brace of a type or function’s body.

// function’s type parameter list 就是
func allItemsMatch
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
    
    }

43 第二十四章 AccessControl

1. You can assign specific access levels to individual types (classes, structures, and enumerations), as well as to properties, methods, initializers, and subscripts belonging to those types. Protocols can be restricted to a certain context, as can global constants, variables, and functions.
2. Modules and Source Files
Swift’s access control model is based on the concept of modules and source files.

A module is a single unit of code distribution—a framework or application that is built and shipped as a single unit and that can be imported by another module with Swift’s import keyword.

A source file is a single Swift source code file within a module (in effect, a single file within an app or framework). Although it is common to define individual types in separate source files, a single source file can contain definitions for multiple types, functions, and so on.

3. Open access and public access --- Default Access Levels for Frameworks
   Internal access --- Default Access Levels for Single-Target Apps
   File-private access
   Private access
   
   Access Levels for Unit Test Targets

When you write an app with a unit test target, the code in your app needs to be made available to that module in order to be tested. By default, only entities marked as open or public are accessible to other modules. However, a unit test target can access any internal entity, if you mark the import declaration for a product module with the @testable attribute and compile that product module with testing enabled.

   //遵循两个规则
   A public variable cannot be defined as having an internal, file-private, or private type, because the type might not be available everywhere that the public variable is used.
   A function cannot have a higher access level than its parameter types and return type, because the function could be used in situations where its constituent types are not available to the surrounding code.
   
4. Default Access Levels: Unless otherwise specified, the default access level is internal
5. The access control level of a type also affects the default access level of that type’s members (its properties, methods, initializers, and subscripts). If you define a type’s access level as private or file private, the default access level of its members will also be private or file private. If you define a type’s access level as internal or public (or use the default access level of internal without specifying an access level explicitly), the default access level of the type’s members will be internal.

public class SomePublicClass {                  // explicitly public class
    public var somePublicProperty = 0            // explicitly public class member
    var someInternalProperty = 0                 // implicitly internal class member
    fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}
 
class SomeInternalClass {                       // implicitly internal class
    var someInternalProperty = 0                 // implicitly internal class member
    fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}
 
fileprivate class SomeFilePrivateClass {        // explicitly file-private class
    func someFilePrivateMethod() {}              // implicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}
 
private class SomePrivateClass {                // explicitly private class
    func somePrivateMethod() {}                  // implicitly private class member
}

6. The access level for a tuple type is the most restrictive access level of all types used in that tuple.

7. The access level for a function type is calculated as the most restrictive access level of the function’s parameter types and return type. You must specify the access level explicitly as part of the function’s definition if the function’s calculated access level does not match the contextual default.
 
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // function implementation goes here
}

8. The individual cases of an enumeration automatically receive the same access level as the enumeration they belong to. You cannot specify a different access level for individual enumeration cases.

In the example below, the CompassPoint enumeration has an explicit access level of “public”. The enumeration cases north, south, east, and west therefore also have an access level of “public”:

public enum CompassPoint {
    case north
    case south
    case east
    case west
}
Raw Values and Associated Values

The types used for any raw values or associated values in an enumeration definition must have an access level at least as high as the enumeration’s access level. You cannot use a private type as the raw-value type of an enumeration with an internal access level, for example.

9. Nested types defined within a private type have an automatic access level of private. Nested types defined within a file-private type have an automatic access level of file private. Nested types defined within a public type or an internal type have an automatic access level of internal. If you want a nested type within a public type to be publicly available, you must explicitly declare the nested type as public.

10. You can subclass any class that can be accessed in the current access context. A subclass cannot have a higher access level than its superclass. An override can make an inherited class member more accessible than its superclass version.It is even valid for a subclass member to call a superclass member that has lower access permissions than the subclass member, as long as the call to the superclass’s member takes place within an allowed access level context.( within the same source file or within the same module)

public class A {
    private func someMethod() {}
}
 
internal class B: A {
    override internal func someMethod() {
    super.someMethod()
    }
}

11. A constant, variable, or property cannot be more public than its type. It is not valid to write a public property with a private type, for example. Similarly, a subscript cannot be more public than either its index type or return type.

If a constant, variable, property, or subscript makes use of a private type, the constant, variable, property, or subscript must also be marked as private:

private var privateInstance = SomePrivateClass()

12. You can give a setter a lower access level than its corresponding getter, to restrict the read-write scope of that variable, property, or subscript. You assign a lower access level by writing fileprivate(set), private(set), or internal(set) before the var or subscript introducer.This rule applies to stored properties as well as computed properties. Even though you do not write an explicit getter and setter for a stored property, Swift still synthesizes an implicit getter and setter for you to provide access to the stored property’s backing storage. Use fileprivate(set), private(set), and internal(set) to change the access level of this synthesized setter in exactly the same way as for an explicit setter in a computed property.

public struct TrackedString {
    public private(set) var numberOfEdits = 0
    public var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
    public init() {}
}

13. Initializers

Custom initializers can be assigned an access level less than or equal to the type that they initialize. The only exception is for required initializers (as defined in Required Initializers). A required initializer must have the same access level as the class it belongs to.
As with function and method parameters, the types of an initializer’s parameters cannot be more private than the initializer’s own access level.

14. If you define a public protocol, the protocol’s requirements require a public access level for those requirements when they are implemented

If you define a new protocol that inherits from an existing protocol, the new protocol can have at most the same access level as the protocol it inherits from. You cannot write a public protocol that inherits from an internal protocol.

 if a public type conforms to an internal protocol, the type’s implementation of each protocol requirement must be at least “internal”.
 
 Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add have a default access level of internal. 

44 第二十五章 高级操作符

1. Bitwise NOT Operator (~) 

let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits  // equals 11110000

2. Bitwise AND Operator (&)

let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // equals 00111100

3. Bitwise OR Operator (|)

let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // equals 11111110

4. Bitwise XOR Operator (^)  
   The bitwise XOR operator, or “exclusive OR operator” (^), compares the bits of two numbers. The operator returns a new number whose bits are set to 1 where the input bits are different and are set to 0 where the input bits are the same:
   
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // equals 00010001

5. Bitwise Left and Right Shift Operators  (<<) (>>) 
Bitwise left and right shifts have the effect of multiplying or dividing an integer by a factor of two. Shifting an integer’s bits to the left by one position doubles its value, whereas shifting it to the right by one position halves its value.

The bit-shifting behavior for unsigned integers is as follows:

Existing bits are moved to the left or right by the requested number of places.
Any bits that are moved beyond the bounds of the integer’s storage are discarded.
Zeros are inserted in the spaces left behind after the original bits are moved to the left or right.
This approach is known as a logical shift.

6. Overflow Operators
Swift provides three arithmetic overflow operators that opt in to the overflow behavior for integer calculations. These operators all begin with an ampersand (&):

Overflow addition (&+)
Overflow subtraction (&-)
Overflow multiplication (&*)

7. Numbers can overflow in both the positive and negative direction.
8. Precedence and Associativity

Operator precedence gives some operators higher priority than others; these operators are applied first.
Operator associativity defines how operators of the same precedence are grouped together—either grouped from the left, or grouped from the right。

9. Operator Methods

Classes and structures can provide their own implementations of existing operators. This is known as overloading the existing operators.

struct Vector2D {
    var x = 0.0, y = 0.0
}
 
extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
}

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector is a Vector2D instance with values of (5.0, 5.0)

10. Prefix and Postfix Operators

The example shown above demonstrates a custom implementation of a binary infix operator. Classes and structures can also provide implementations of the standard unary operators. Unary operators operate on a single target. They are prefix if they precede their target (such as -a) and postfix operators if they follow their target (such as b!).

You implement a prefix or postfix unary operator by writing the prefix or postfix modifier before the func keyword when declaring the operator method:

extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
}

11. Compound Assignment Operators

Compound assignment operators combine assignment (=) with another operation. For example, the addition assignment operator (+=) combines addition and assignment into a single operation. You mark a compound assignment operator’s left input parameter type as inout, because the parameter’s value will be modified directly from within the operator method.

The example below implements an addition assignment operator method for Vector2D instances:

extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right
    }
}
Because an addition operator was defined earlier, you don’t need to reimplement the addition process here. Instead, the addition assignment operator method takes advantage of the existing addition operator method, and uses it to set the left value to be the left value plus the right value:

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original now has values of (4.0, 6.0)
NOTE

It is not possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) cannot be overloaded.

12. Custom Operators

You can declare and implement your own custom operators in addition to the standard operators provided by Swift. For a list of characters that can be used to define custom operators, see Operators.

New operators are declared at a global level using the operator keyword, and are marked with the prefix, infix or postfix modifiers:

prefix operator +++
The example above defines a new prefix operator called +++. This operator does not have an existing meaning in Swift, and so it is given its own custom meaning below in the specific context of working with Vector2D instances. For the purposes of this example, +++ is treated as a new “prefix doubling” operator. It doubles the x and y values of a Vector2D instance, by adding the vector to itself with the addition assignment operator defined earlier. To implement the +++ operator, you add a type method called +++ to Vector2D as follows:

extension Vector2D {
    static prefix func +++ (vector: inout Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
}
 
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled now has values of (2.0, 8.0)
// afterDoubling also has values of (2.0, 8.0)

你可能感兴趣的:(【Swift官方助读】重点摘取)