---
# System prepended metadata

title: '<font color="#8A2BE2">[W2-1]</font> Programming in Swift: Functions and Types'
tags: ['[Kodeco IOS]']

---


<font color="#8A2BE2">[W2-1]</font> Programming in Swift: Functions and Types
===
快速了解本篇目錄
[TOC]

[Part1] Functions
===

# 1. intro 


| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/6BkLZM5.png)| ![](https://i.imgur.com/WyX9JzG.png)| |



| Part1 | Part2 | Part3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/bRQdsHj.png)     | ![](https://i.imgur.com/b8GTZ3l.png)| ![](https://i.imgur.com/3Kns8Ya.png)|



| Part4 | Part5 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/8k6RweS.png)| ![](https://i.imgur.com/L9W7r4b.png)|      |




# 2. 2. Review Functions



![Uploading file..._kzq4io9ep]()
![](https://i.imgur.com/tRzEUMk.png)![Uploading file..._ygkextdhe]()

![](https://i.imgur.com/2o22A7o.png)


## 單純的函式
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------

//: Every function will have a name, parameter list, and body.
//:
//: Parameter lists can be empty.
//單純的函式
func printMeow() {
  print("Meow!")
}

printMeow()                                         //Meow!
```

## 函式帶有一個參數     (參數名  型別)
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------


//函式帶有一個參數     (參數名  型別)
func printPassStatus(grade: Int) {
  print(grade >= passingGrade ? "You passed!" : "Glue != food.")
}

//: When you call a function with parameters, you provide values as arguments for those parameters.
//              (參數名          值)
printPassStatus(grade: jessyGrade)                   //Glue != food.
```

## 函式帶有兩個參數    (參數1)       (參數2 直接賦值)

```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------


//函式帶有兩個參數     (參數1)       (參數2 直接賦值)
func printPassStatus(grade: Int, lowestPass: Int = passingGrade) {
  print(grade >= lowestPass ? "Good kitty!" : "Keep your paws off the table!")
}

//: When you call a function, you don't need to provide arguments for parameters with a default value.
//呼叫函式        (只給一個參數)
printPassStatus(grade: jessyGrade)                  //Keep your paws off the table!
//呼叫函式        (只給一個參數，      改變原本賦值的值)
printPassStatus(grade: ozmaGrade, lowestPass: 80)   //Good kitty!
```

## 函式for標籤
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------


//                  for 標籤
func printPassStatus(for grade: Int, lowestPass: Int = passingGrade) {
  print(grade >= lowestPass ? "You've earned a treat." : "🙃")
}

//呼叫就不用寫上參數名
//              for     參數值1,   參數值2名   參數值2值
printPassStatus(for: ozmaGrade, lowestPass: 80)    //You've earned a treat.
```

## _ no argument label
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------


//                   no argument label
func printHighestGrade(_ grade1: Int, _ grade2: Int) {
  print(grade1 >= grade2 ? grade1 : grade2)
}

//不需要參數名，只要參數值
//                 參數1值       參數2值
printHighestGrade(jessyGrade, ozmaGrade)

```

## 函式回傳值

```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------


//函式回傳值
//                                                                   回傳布林值
func getPassStatus(for grade: Int, lowestPass: Int = passingGrade) -> Bool {
  return grade >= lowestPass
}

let jessyPassStatus = getPassStatus(for: jessyGrade)
```

## 函式回傳值因為裡面只有一行，可以不要寫return
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 41
let ozmaGrade = 87
// --------------------------------------


//函式回傳值因為裡面只有一行，可以不要寫return
func getPassStatus2(for grade: Int, lowestPass: Int = passingGrade) -> Bool {
//可以不寫return
  grade >= lowestPass
}

let ozmaPassStatus = getPassStatus2(for: ozmaGrade, lowestPass: 80)

```

# 3. Challenge: Functions

## 我寫的
```swift=
// TODO: Write solution here
/*
 1. 兩個參數都是字串
 2. 其中一參數已定義好default value
 3. 回傳字串
 4. 結合兩個參數，回傳result
 */

let familyName = "Yin"
let fullName = ""
func getMyName(firstName: String, lastName: String = familyName ) ->String {
    return firstName + " " + lastName   //"Chou Po Yin"
}

getMyName(firstName: "Chou Po")         //"Chou Po Yin"
```

## ray寫的
```swift=
//------------------------------------------

//函式參數2已定義好
func generateTwitterHandle(name: String, anotherWord word: String = "Meow") -> String {
  name.lowercased() + word  //回傳ozmaMeow
}
//呼叫韓式只要寫參數1就可
generateTwitterHandle(name: "Ozma")

//------------------------------------------




//函式沒參數標籤_ 呼叫時不用寫參數名
func deutschify(_ word1: String, _ word2: String = "katzen") -> String {
    
    //.randomElement()!是在陣列內隨機找出一個元素
  let adjective = ["Frölich", "Rund", "Salzig", "Schwarze"].randomElement()!
  let ending = ["schule", "keit", "maler", "maschine"].randomElement()!
  
    //回傳 形容詞+參數1+參數2+結尾
  return adjective + word1 + word2 + ending
}


//呼叫時不用寫參數名
deutschify("swifty")            //隨機形容詞陣列元素swiftykatzen隨機結尾詞陣列元素 "Frölich swifty katzen maschine"
deutschify("arctic", "tree")    //隨機形容詞陣列元素arctictree隨機結尾詞陣列元素  "Rund arctic tree schule"
```

# 4. Overloading



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/zw7ueY9.png)| ![](https://i.imgur.com/Z7o9Y34.png)|      |


## 函式名子重複，依照呼叫參數分辨要使用哪個函式
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 49
let ozmaGrade = 87
let ozmaAllGrades = [60, 96, 87, 42]
// --------------------------------------

重複命名1
func getPassStatus(for grade: Int) -> Bool {
    grade >= passingGrade
}

重複命名2
func getPassStatus(for grade: Int, lowestPass: Int) -> Bool {
    grade >= passingGrade
}

//                      87               80
getPassStatus(for: ozmaGrade, lowestPass: 80)   //使用重複命名2函式 87>=80 true
//                      49
getPassStatus(for: jessyGrade)                  //使用重複命名1函式 49>=50 false
```

## 避免狀況發生，在命名函式時使用default value
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 49
let ozmaGrade = 87
let ozmaAllGrades = [60, 96, 87, 42]
// --------------------------------------


//參數使用default values
//                                       dafalit value定義為50
func getPassStatus(for grade: Int, lowestPass: Int = passingGrade) -> Bool {
    grade >= lowestPass
}
//                      87               80
getPassStatus(for: ozmaGrade, lowestPass: 80)   //使用下面函式 87>=80 true

//                      49
getPassStatus(for: jessyGrade)                  //使用上面函式 49>=50 false       如果只帶一個參數，第二個就一定要賦值

```

## 函式名一樣，可以用選的 (陣列)
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 49
let ozmaGrade = 87
let ozmaAllGrades = [60, 96, 87, 42]
// --------------------------------------

重複命名1
//參數使用default values
//                                                         50
func getPassStatus(for grade: Int, lowestPass: Int = passingGrade) -> Bool {
    grade >= lowestPass
}
//                      87               80
getPassStatus(for: ozmaGrade, lowestPass: 80)   //使用下面函式 87>=80 true

//                      49
getPassStatus(for: jessyGrade)                  //使用上面函式 49>=50 false       如果只帶一個參數，第二個就一定要賦值


重複命名2
func getPassStatus(for grades: [Int]) -> Bool {
    var totalGrade = 0
    for grade in grades {
        totalGrade += grade
    }
    let averageGrade = totalGrade / grades.count
    return averageGrade >= passingGrade
}

getPassStatus(for: ozmaGrade)       //true

```
![](https://i.imgur.com/uWyfuGb.png)


## 使用stride functions
```swift=
關於from to 
for i in stride(from: 10 , to: 0, by: -2) {
    print(i)        // 10   8   6   4   2
}

關於from through
for i in stride(from: 10 , through: 0, by: -2) {
    print(i)        // 10   8   6   4   2   0
}

```

## 重複命名回傳會報錯
```swift=
func getValue() -> Int {
    return 13
}


func getValue() -> String {
    return "meow"
}

let value = getValue()
```
![](https://i.imgur.com/7qjAZpf.png)


## 重複命名回傳 函式名子前面要加上值
```swift=
func getValue() -> Int {
    return 13
}


func getValue() -> String {
    return "meow"
}

//let value = getValue()   不能這樣呼叫回傳，會報錯
let intValue1: Int = getValue()     //13
let intValue2: String = getValue()  //"meow"
```

# 5. Advanced Parameters

## 函式多個參數 (陣列不行)
```swift=
// --------------------------------------
let passingGrade = 50
let jessyGrade = 49
let ozmaGrade = 87
let ozmaAllGrades = [60, 96, 87, 42]
// --------------------------------------

//: ### Variadic Parameters

print(jessyGrade, ozmaGrade, "meow")


//函式多個參數
func getHighestGrade(for grades: Int...) -> Int {
    grades.max() ?? 0 //如果有最大值 回傳最大值，如果值不存在 回傳0
}

getHighestGrade()                           //0
getHighestGrade(for: jessyGrade, ozmaGrade) //87

//getHighestGrade(for: ozmaAllGrades)         //參數不能帶陣列
```

## inout參數

Swift 的 function 中的參數都是以 pass-by-value 的方式傳遞，當 value 傳遞到 function 內，value 會先 copy 一份（也就是 let _value = value），因此 function 中的參數預設都是以常數為型態，無法修改。

<font color = "red">那如果在有些需求當中，我們就是想要直接修改參數值呢？這時就要用到 inout 這個關鍵字：</font>

inout 為 copy-in copy-out 的意思，也有人稱為 call by value result，顧名思義，加上 inout 後的行為就是 copy 一份進來，再 copy 一份出去

```swift=
// --------------------------------------
var count = 0
// --------------------------------------

//參數函式 inout
func incrementAndPrint(_ value: inout Int) {
    value += 1
    print(value)
}

incrementAndPrint(&count)   //1
incrementAndPrint(&count)   //2
incrementAndPrint(&count)   //3
print("\(count)")           //3
```

# 6. Challenge: Overloads & Parameters

## Challenge 1

Write two possible overloads for the function below. You can use...

a different number of parameters
different argument labels
different parameter types
different return types

```swift=
//函式1
//                       參數2名by
//                           參數2值multiplier
func multiply(number: Int, by multiplier: Int) -> Int {
  return number * multiplier
}

// TODO: Write solution here
//函式2
func multiply(_ number: Int, _ multiplier: Int) -> Int {
  return number * multiplier
}

//函式3
let number3 = 3
func multiply(for number: Int, by multiplier: Int = number3) -> Int {
    return number * multiplier
  }

multiply(number: 5, by: 2)                 //函式1 回傳10      第一個參數5    第二個參數2
multiply(4, 9)                             //函式2 回傳36
multiply(for: 4)                           //函式3 回傳12      因為有for第一個參數4不用寫型別    第二個參數已定義3
```

## Challenge 2

Eliminate the overloads below by using a default value for a parameter.
```swift=
// --------------------------------------
////函式1
//func printMultipleOf(multiplier: Int, number: Int) {
//  print("\(multiplier) * \(number)  = \(multiplier * number)")
//}
//
////函式2
//func printMultipleOf(multiplier: Int) {
//  print("\(multiplier) * 1)  = \(multiplier * 1)")
//}
// --------------------------------------


//函式3
func printMultipleOf(multiplier: Int, number: Int = 1) {
  print("\(multiplier) * \(number)  = \(multiplier * number)")
}

// --------------------------------------
printMultipleOf(multiplier: 7)                  //函式3   7
printMultipleOf(multiplier: 11, number: 4)      //函式3   44
// --------------------------------------


```

## Challenge 3

1 - Change the function below so that it can modify the right parameter. 2 - Call the function!

```swift=
//寫法1
var score1 = 50

//          參數名  型別
//                 scroe要改加上inout
//                              參數2名稱  參數2變數名
func update1(score: inout Int, withPoints points:  Int) {    //參數2名稱是points
  score += points
}

//      參數名  值
//          scroe要改加上&
update1(score: &score1, withPoints: 100)   //參數1 50    參數2 100 結果150
// update1(score: &score1, points: 100)   //報錯，第二參數是要寫參數2名稱withPoints(不是參數2變數名points)
score1                                    //score是150


//寫法2
var score2 = 60

func update2(score: inout Int, withPoints:  Int) {
  score += withPoints
}

update2(score: &score2, withPoints: 100)   //160
score2                                     //160
```
![](https://i.imgur.com/p8WnKzh.png)



# 7. Functions as Parameters

## 函式賦值 給 變數 (什麼竟然可以這樣？)
Functions are data types, and can be assigned to variables and constants just like Int and String.
```swift=
func add(number1: Int, number2: Int) -> Int {
    number1 + number2
}

var function = add

function(4,2)   //6

func subtract(number1: Int, number2: Int) -> Int {
    number1 - number2
}

function = subtract    //所以現在function變數，就有func subtract函式的能力，變數也是函式了

function(4,2)   //變數function目前有func subtract的能力
                //得到2，因為4-2 = 2
```

## 函式內函式
Functions can use functions as parameter and return types. Functions that do this are called  "higher-order functions"

### 方法1基本
<font color =red>看不懂</font>
<font color =red>_ operate: (Int, Int) -> Int</font>
```swift=
//三個參數          operate        ,a值                    ,b值
func printResult(_ operate: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    let result = operate(a, b)
    print(result)
}

printResult(add, 4, 2)          //6
printResult(subtract, 4, 2)     //2
printResult(+, 4, 2)            //6
printResult(-, 40, 2)           //38
printResult(*, 40, 2)           //80
printResult(/, 20, 2)           //10
```

### 方法2 typealias
```swift=
typealias Operate = (Int, Int) -> Int

//三個參數          operate        ,a值                    ,b值
func printResult(_ operate: Operate, _ a: Int, _ b: Int) {
    let result = operate(a, b)
    print(result)
}

printResult(add, 4, 2)          //6
printResult(subtract, 4, 2)     //2
printResult(+, 4, 2)            //6
printResult(-, 40, 2)           //38
printResult(*, 40, 2)           //80
printResult(/, 20, 2)           //10
```
![](https://i.imgur.com/2o22A7o.png)


![](https://i.imgur.com/tRzEUMk.png)


# 8. Conclusion

| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/DdRMqvh.png)| ![](https://i.imgur.com/Nug2Bfr.png)|    |


[Part2] Closures
===

# 9. Introduction


| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/wAaiNTg.png)| ![](https://i.imgur.com/PJeGUir.png)||



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
|  ![](https://i.imgur.com/03sklyM.png)| ![](https://i.imgur.com/hlVMjHL.png)     |      |

# 10. Closures



| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/ZtzWUq1.png)| ![](https://i.imgur.com/9FY1V21.png)| Text     |

![](https://i.imgur.com/QVToQfJ.png)


```swift=
// --------------------------------------
typealias Operate = (Int, Int) -> Int

func add(a: Int, b: Int) -> Int {
  a + b
}

func printResult(_ operate: Operate, _ a: Int, _ b: Int) {
  let result = operate(a, b)
  print(result)
}
// --------------------------------------

var operate = add

//寫法1
//var addClosure: (Int, Int) -> Int

//寫法2-1
//var addClosure: Operate = { (a: Int, b: Int) -> Int in
//    return a + b
//}

//寫法2-2 省略return
//var addClosure: Operate = { (a: Int, b: Int) -> Int in
//     a + b
//}

//寫法2-3 省略: Operate
var addClosure = { (a: Int, b: Int) -> Int in
     a + b
}

//錯誤寫法 2-4 不需要加入argument label
//var addClosure = { (num1 a: Int, num2 b: Int) -> Int in
//     a + b
//}

//錯誤寫法 2-5 不需要加入default value
//var addClosure = { (a: Int, b: Int = 10) -> Int in
//     a + b
//}

add(a: 7, b: 3)     //呼叫函式10
operate(7, 3)       //變數(內呼叫函式)10
addClosure(7, 3)    //10    不需要argument label


//以下都是相同呼叫答案
printResult(add, 4, 5)          //9
printResult(operate, 4, 5)      //9
printResult(addClosure, 4, 5)   //9
printResult(+, 4, 5)            //9


//看不懂
//inline closure 不容易被既有函式 或 operator改變
printResult(                        //130
    { (a: Int, b: Int) -> Int in    //參數1
        a * b + 100
    },
    3, 10
)
```


![](https://i.imgur.com/QVToQfJ.png)
![](https://i.imgur.com/E6yfjcu.png)

# 11. Challenge: Closures

## Challenge 1

Create a closure version of the function below.
Try out the function & closure!

```swift=
// --------------------------------------
func calculateFullName(firstName: String, lastName: String?) -> String {
  firstName + " " + (lastName ?? "")
}
// --------------------------------------

// TODO: Write solution here
//呼叫既有函式
calculateFullName(firstName: "Chou Po", lastName: "Yin")                //Chou Po Yin

//使用closure
let myName = { (firstName: String, lastName: String?) -> String in      //Chou Po Yin
    firstName + " " + (lastName ?? "")
}

myName("Chou Po", "Yin")
```

## Challenge 2

Call the printResult function below
Use an inline closure as an argument

```swift=
// --------------------------------------
typealias Operate = (Double, Double) -> Double

func printResult(_ operate: Operate, _ a: Double, _ b: Double) {
  let result = operate(a, b)
  print(result)
}
// --------------------------------------

// TODO: Write solution here

//5.0     3^2 + 4^2 開根號等於5
printResult(
    { (a, b) -> Double in
      ((a * a) + (b * b)).squareRoot()
    },
    3, 4
)
```

# 12. Closure Syntax



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/mgZS0gc.png)| ![](https://i.imgur.com/4UAWZKL.png)|      |



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/CoOfof4.png)| ![](https://i.imgur.com/PDV9Auv.png)|      |



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/QSyC8k7.png)| ![](https://i.imgur.com/qIP6I0G.png)|      |

## 各種寫法
```swift=
// --------------------------------------
typealias Operate = (Int, Int) -> Int
// --------------------------------------

let longClosure = { (a: Int, b: Int) -> Int in
    a * b
}

let noParameterTypes :Operate = { (a, b) -> Int in
    a * b
}

let noReturnTypes :Operate = { (a, b) in
    a * b
}

let shortClosure :Operate = { $0 * $1 }

longClosure(4,2)        //8
noParameterTypes(4,2)   //8
noReturnTypes(4,2)      //8
shortClosure(4,2)       //8

//寫法1   OK
//let voidClosure: () -> Void = { () -> Void in
//    print("Yay, Swift")
//}

//寫法2   OK
//let voidClosure: () -> Void = {
//    print("Yay, Swift")
//}

////寫法3 不能用在parameter list  OK
//let voidClosure: () -> () = {
//    print("Yay, Swift")
//}

//寫法4   OK
let voidClosure: () -> Void = {
    print("Yay, Swift")
}

voidClosure()                                   //Yay, Swift
```

## operate在後
```swift=
//operate在後
// --------------------------------------
func printResult(_ a: Int, _ b: Int, _ operate: Operate) {
  print(operate(a, b))
}
// --------------------------------------
printResult(10, 3, { $0 * $1 + 10 })    //40
printResult(10, 3) { $0 * $1 + 10 }     //40
    
```



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/T1osKGT.png)     | ![](https://i.imgur.com/UfHuiEM.png)|      |

# 13. Challenge: Closure Syntax
```swift=
// --------------------------------------
let copyLines = { (offense: String, repeatCount: Int) -> Void in
  print( String(repeating: "I must not \(offense).", count: repeatCount) )
}
// --------------------------------------

// TODO: Write solution here

使用 No parameter types

let copyLines_2: (String, Int) -> Void = { offense, repeatCount -> Void in
  print( String(repeating: "I must not \(offense).", count: repeatCount) )
}



使用 No parameter or return types

let copyLines_3: (String, Int) -> Void = { offense, repeatCount in
  print( String(repeating: "I must not \(offense).", count: repeatCount) )
}



使用 No parameter names Try passing the same values into each closure. Their printed results should match!

let copyLines_4: (String, Int) -> Void = {
  print( String(repeating: "I must not \($0).", count: $1) )
}

copyLines("tell lies", 5)        //I must not tell lies.I must not tell lies.I must not tell lies.I must not tell lies.I must not tell lies.
copyLines_2("tell lies", 5)
copyLines_3("tell lies", 5)
copyLines_4("tell lies", 5)
```

# 14. forEach & map

map有回傳值
| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/nREYW1Q.png)     | ![](https://i.imgur.com/k15itpq.png)     |      |


```swift=
var prices = [1.50, 10.00, 4.99, 2.30, 8.19]

基礎 for
for price in prices {
  print(price)
}

forEach寫法
prices.forEach { (price) in
  print(price)
}

forEach 更短
prices.forEach { print($0) }
```

```swift=
// `map` as a `for` loop
var arrayForSalePrices: [Double] = []

基礎for
for price in prices {
  arrayForSalePrices.append(price * 0.9)
}
arrayForSalePrices

map寫法
let salePrices = prices.map { $0 * 0.9 }

map寫法，只取Double小數點後兩位
let priceLabels = salePrices.map { (price) in
  String(format: "%.2f", price)
}

```






| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/qPOMPwg.png)     | ![](https://i.imgur.com/6Y3cwN5.png)     |      |









# 15. compactMap & flatMap

## compactMap
```swift=
// --------------------------------------
let userInput = ["meow!", "15", "37.5", "seven"]
// --------------------------------------

// `compactMap` as a `for` loop
var arrayForValidInput: [Int] = []

一般for寫法 得出陣列中單純數字
for input in userInput {
  guard let input = Int(input) else {
    continue
  }
  arrayForValidInput.append(input)
}
arrayForValidInput        //[15]


compactMap寫法
let validInput = userInput.compactMap { input in
  Int(input)
}
```

## flatMap
合併成單一集合型別的時候，flatMap 就大派用場了
```swift=
let marks = [[3, 4, 5], [2, 5, 3], [1, 2, 2], [5, 5, 4], [3, 5, 3]]

使用傳統的 for-in 迴圈，我們可以獲取單一陣列之中的所有數值：

var allMarks = [Int]()
for marksArray in marks {
    allMarks += marksArray
}

然而，如果我們使用 flatMap 高階函數，就可以避免這些手動工作：

let allMarks = marks.flatMap { (array) -> [Int] in
    return array
}

我們也可以進一步透過速記參數來精簡上述的程式碼：

let allMarks = marks.flatMap { $0 }


結果
print(allMarks)
// Prints [3, 4, 5, 2, 5, 3, 1, 2, 2, 5, 5, 4, 3, 5, 3]
```

Kodeco寫法
```swift=
// --------------------------------------
let arrayOfDwarfArrays = [
  ["Sleepy", "Grumpy", "Doc", "Bashful", "Sneezy"],
  ["Thorin", "Nori", "Bombur"]
]
// --------------------------------------

let dwarvesAfterM = arrayOfDwarfArrays.flatMap { dwarves -> [String] in
  var afterM: [String] = []
  for dwarf in dwarves where dwarf > "M" {
    afterM.append(dwarf)
  }
  return afterM
}

```


# 16. Challenge: Closures & Collections

## Challenge 1 - forEach & map
There are two for loops below. Rewrite one of them using forEach and the other with map
```swift=
//自定義類
class Student {
  let name: String
  var grade: Int
  var pet: String?
  var libraryBooks: [String]
  
    //使用init
  init(name: String, grade: Int, pet: String? = nil, libraryBooks: [String]) {
    self.name = name
    self.grade = grade
    self.pet = pet
    self.libraryBooks = libraryBooks
  }
  
    //函式1
  func getPassStatus(lowestPass: Int = 50) -> Bool {
    grade >= lowestPass
  }
  
    //函式2
  func earnExtraCredit() {
    grade += 10
  }
}

let chris = Student(name: "Chris", grade: 49, pet: "Mango", libraryBooks: ["The Book of Atrus", "Living by the Code", "Mastering Git"])
let sam = Student(name: "Sam", grade: 99, pet: nil, libraryBooks: ["Mastering Git"])
let catie = Student(name: "Catie", grade: 75, pet: "Ozma", libraryBooks: ["Hogfather", "Good Omens"])
let andrea = Student(name: "Andrea", grade: 88, pet: "Kitten", libraryBooks: ["Dare to Lead", "The Warrior's Apprentice"])

let students = [chris, sam, catie, andrea]

/*
 其實裡面是長這樣
 students = [
              Student(name: "Chris", grade: 49, pet: "Mango", libraryBooks: ["The Book of Atrus", "Living by the Code", "Mastering Git"])
              Student(name: "Sam", grade: 99, pet: nil, libraryBooks: ["Mastering Git"]),
              Student(name: "Catie", grade: 75, pet: "Ozma", libraryBooks: ["Hogfather", "Good Omens"]),
              Student(name: "Andrea", grade: 88, pet: "Kitten", libraryBooks: ["Dare to Lead", "The Warrior's Apprentice"])
            ]
 */
// --------------------------------------


//使用for給學生加十分
for student in students {
  student.earnExtraCredit()
}

//使用forEach給學生加十分
students.forEach{ (student) in
    student.earnExtraCredit()
}

/*
 students = [
              Student(name: "Chris", grade: 69, pet: "Mango", libraryBooks: ["The Book of Atrus", "Living by the Code", "Mastering Git"])
              Student(name: "Sam", grade: 119, pet: nil, libraryBooks: ["Mastering Git"]),
              Student(name: "Catie", grade: 95, pet: "Ozma", libraryBooks: ["Hogfather", "Good Omens"]),
              Student(name: "Andrea", grade: 108, pet: "Kitten", libraryBooks: ["Dare to Lead", "The Warrior's Apprentice"])
            ]
 */

//使用for建立陣列，放每個學生的圖書館書籍
//var classLibraryBooks: [[String]] = []
//for student in students {
//  classLibraryBooks.append(student.libraryBooks)
//}

//使用map
let classLibraryBooks = students.map { (student) -> [String] in
    student.libraryBooks
}
print(classLibraryBooks)    //[["The Book of Atrus", "Living by the Code", "Mastering Git"], ["Mastering Git"], ["Hogfather", "Good Omens"], ["Dare to Lead", "The Warrior\'s Apprentice"]]
```

## Challenge 2 - compactMap
Replace the for loop below with compactMap. It will filter out the nil values for you!
```swift=

//var classPets: [String] = []
//for student in students {
//  if let pet = student.pet {
//    classPets.append(pet)
//  }
//}
//
//print(classPets)    //["Mango", "Ozma", "Kitten"]

//使用compactMap
//let classPets = students.compactMap { (student) -> String? in
//    student.pet
//}

//[["The Book of Atrus", "Living by the Code", "Mastering Git"], ["Mastering Git"], ["Hogfather", "Good Omens"], ["Dare to Lead", "The Warrior\'s Apprentice"]]


let classPets = students.compactMap { $0.pet }  //[["The Book of Atrus", "Living by the Code", "Mastering Git"], ["Mastering Git"], ["Hogfather", "Good Omens"], ["Dare to Lead", "The Warrior\'s Apprentice"]]

```

## Challenge 3 - flatMap
In Challenge 1 you created libraryBooks, an array of String arrays! Try using flatMap to flatten all of the books into a single String array.
```swift=
let classLibraryBooks = students.flatMap { (student) -> [String] in
  student.libraryBooks
}
print(classLibraryBooks)

```


# 17. filter, reduce, & sort
![](https://i.imgur.com/CM8iXtl.png)
![](https://i.imgur.com/BUIvio4.png)
![](https://i.imgur.com/SsqoXp6.png)

# filter
```swift=
// --------------------------------------
let arrayOfDwarfArrays = [
  ["Sleepy", "Grumpy", "Doc", "Bashful", "Sneezy"],
  ["Thorin", "Nori", "Bombur"]
]


//舊寫法
// --------------------------------------
//let dwarvesAfterM = arrayOfDwarfArrays.flatMap { dwarves -> [String] in
//  var afterM: [String] = []
//  for dwarf in dwarves where dwarf > "M" {
//    afterM.append(dwarf)
//  }
//  return afterM
//}
// --------------------------------------

// --------------------------------------


//從Z->A
let dwarvesAfterM2 = arrayOfDwarfArrays.flatMap { dwarves -> [String] in      //["Sleepy", "Sneezy", "Thorin", "Nori"]
  dwarves.filter { $0 > "M" }
}//.sorted()


//從A->Z
let dwarvesAfterM = arrayOfDwarfArrays.flatMap { dwarves -> [String] in      //["Nori", "Sleepy", "Sneezy", "Thorin"]
  dwarves.filter { $0 > "M" }
}.sorted()

```

# reduce
![](https://i.imgur.com/4BVHtOC.png =50%x)



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/QODNLaq.png)     | ![](https://i.imgur.com/1oQKG1O.png)|      |






```swift=
// --------------------------------------
let ozmaGrades = [60, 96, 87, 42]

//func getPassStatus(for grades: [Int], lowestPass: Int) -> Bool {
//  var totalGrade = 0
//  for grade in grades {
//    totalGrade += grade
//  }

//  return (totalGrade / grades.count) > lowestPass
//}
// --------------------------------------

func getPassStatus(for grades: [Int], lowestPass: Int) -> Bool {
  let totalGrade = grades.reduce(0, +) //{ total, grade -> Int in
//    total + grade
//  }
  return (totalGrade / grades.count) > lowestPass
}

//使用函式
getPassStatus(for: ozmaGrades, lowestPass: 60)          //true

```


## reduce(into:)
```swift=
// --------------------------------------
var stock = [1.50: 5, 10.00: 2, 4.99: 20, 2.30: 5, 8.19: 30]
// --------------------------------------


////印出[99.80000000000001, 11.5, 20, 245.7, 7.5]
let stockSums = stock.reduce(into: []) { (result, item) in
  result.append(item.key * Double(item.value))
}

```


# Sorting Methods
| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/gcy3W96.png)     | ![](https://i.imgur.com/0iJKXdn.png)     |      |


```swift=

// --------------------------------------
var names = ["Zeus", "Poseidon", "Ares", "Demeter"]
// --------------------------------------
```

## sort() & sort(by:) - Sorts in place (mutates the original)
```swift=
names.sort()                        //["Ares", "Demeter", "Poseidon", "Zeus"]
names.sort { (a, b) -> Bool in      //["Zeus", "Poseidon", "Demeter", "Ares"]
  a > b
}
names.sort(by: >)                   //["Zeus", "Poseidon", "Demeter", "Ares"]
```

## sorted() & sorted(by:) - Returns a new collection that is sorted

```swift=
let longToShortNames = names.sorted {
  $0.count > $1.count
}

longToShortNames                              //["Poseidon", "Demeter", "Zeus", "Ares"]
names                                         //["Zeus", "Poseidon", "Demeter", "Ares"]
```


# 18. Challenge: filter, reduce, & sort

# 19. Conclusion


| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/hr2fkXz.png)| ![](https://i.imgur.com/fum1Apn.png)|      |



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/fvlE5CT.png)| ![](https://i.imgur.com/pEBMyZN.png)|      |

| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/E2WMSZG.png)| ![](https://i.imgur.com/oTjysSR.png)|      |




| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/YpkZsGj.png)| ![](https://i.imgur.com/kCD8KY2.png)|      |



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/R6vYJh8.png)| ![](https://i.imgur.com/ByY7pmj.png)|      |



[Part3] Enumerations
===

# 20. Introduction


| Column 1 | Column 2 |   |
| -------- | -------- | ----- |
| ![](https://i.imgur.com/W66nmIh.png)| ![](https://i.imgur.com/qe2nSQS.png)|      |

![](https://i.imgur.com/Gngy1aE.png)



# 21. Enumerations



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/4VX3mH1.png)| ![](https://i.imgur.com/t4WGYPS.png)|      |


![](https://i.imgur.com/iAnMQqP.png)

```swift=
enum Month: Int {
  case january = 1, february, march, april, may, june, july, august, september, october, november, december
}

let month: Month = .october
let rawMonth = Month(rawValue: 3)

//距離12月有幾個月函式   (使用rawValue)
func monthsUntilJingleBells(from month: Month) -> Int {
  Month.december.rawValue - month.rawValue
}

monthsUntilJingleBells(from: .november) //1



enum Season: String, CaseIterable {
  /// ☃️
  case winter
  
  /// 🌸
  case spring
  
  /// 😎
  case summer
  
  /// 🍂
  case autumn
}

Season.winter.rawValue

//使用filter
Season.allCases.filter {
  $0.rawValue.first == "s"
}

```


# 22. Challenge: Enumerations

# 23. Switch Statements

```swift=
enum Month: Int {
  case january = 1, february, march, april, may, june, july, august, september, october, november, december
}

enum Season: String, CaseIterable {
  /// ☃️
  case winter
  /// 🌸
  case spring
  /// 😎
  case summer
  /// 🍂
  case autumn
}

func getSeason(for month: Month) -> Season {
  switch month {
  case .december, .january, .february:
    return .winter
  case .march, .april, .may:
    return .spring
  case .june, .july, .august:
    return .summer
  case .september, .october, .november:
    return .autumn
  }
}

getSeason(for: .august)


```


# 24. More Switch Statements

## Switching on values
```swift=
func getDescription(for number: Int) -> String {
  switch number {
  case 0:
    return "Zero"
  case 1...9:
    return "Between 1 and 9"
  case let negativeNumber where negativeNumber < 0:
    return "Negative"
  case _ where number > .max / 2:
    return "Very large!"
  default:
    return "No Description"
  }
}

getDescription(for: 0)
getDescription(for: 4)
getDescription(for: -52)
getDescription(for: Int.max)
getDescription(for: 15)
```


## Switching on expressions
```swift=

let number = Int.max
let numberIsEven: Bool

switch number % 2 {
case 0:
  numberIsEven = true
default:
  numberIsEven = false
}
```
![](https://i.imgur.com/fvpu0cE.png)

## Switching on multiple values

```swift=
func pointCategory(for coordinates: (Double, Double)) -> String {
  switch coordinates {
  case (0,0):
    return "Origin"
  case (let x, 0):
    return "On the x-axis at \(x)"
  case (0, let y):
    return "On the y-axis at \(y)"
  case _ where coordinates.0 == coordinates.1:
    return "Along y = x"
  case let (x, y) where y == x * x:
    return "Along y = x ^ 2"
  case let (x, y):
    return "No zero coordinates. x = \(x), y = \(y)"
  }
}

pointCategory(for: (0, 0))      //"Origin"
pointCategory(for: (50, 0))     //"On the x-axis at 50.0"
pointCategory(for: (0, 3))      //"On the y-axis at 3.0"
pointCategory(for: (-4, 17))    //"No zero coordinates. x = -4.0, y = 17.0"
pointCategory(for: (2, 4))      //"Along y = x ^ 2"
pointCategory(for: (6, 6))      //"Along y = x"

```




# 25. Challenge: Switch Statements

# 26. Associated Values



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/WxDy6ij.png)| ![](https://i.imgur.com/NxlCygA.png)|      |



```swift=
enum TwoDimensionalPoint {
  case origin
  case onXAxis(Double)
  case onYAxis(Double)
  case noZeroCoordinate(x: Double, y: Double)
}

let coordinates = (0.0, 7.0)
let twoDimensionalPoint: TwoDimensionalPoint

switch coordinates {
case (0, 0):
  twoDimensionalPoint = .origin                     
case (_, 0):
  twoDimensionalPoint = .onXAxis(coordinates.0)
case (0, _):
  twoDimensionalPoint = .onYAxis(coordinates.1)                                 //onYAxis(7.0)
default:
  twoDimensionalPoint = .noZeroCoordinate(x: coordinates.0, y: coordinates.1)
}


//用函式做 Associate Values
func getValues(for point: TwoDimensionalPoint) -> (x: Double, y: Double) {
  switch point {
  case .origin:
    return (0, 0)
  case let .onXAxis(x):
    return (x, 0)
  case .onYAxis(let y):
    return (0, y)
  case let .noZeroCoordinate(x, y):
    return (x, y)
  }
}

getValues(for: .origin)                                             //(x 0, y 0)
getValues(for: .onXAxis(66.6))                                      //(x 66.59999999999999, y 0)
getValues(for: .onYAxis(-3.5))                                      //(x 0, y -3.5)
getValues(for: TwoDimensionalPoint.noZeroCoordinate(x: 5, y: 7))    //(x 5, y 7)
```

# 27. Conclusion

[Part4] Properties & Methods
===

# 28. Introduction


| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/awAKh4X.png)  | ![](https://i.imgur.com/3zvu5n9.png)     |      |


# 29. Stored Properties


| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/9uj11z6.png)     | ![](https://i.imgur.com/HcGOjDR.png)     |      |

| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/zbt7qWX.png)     | ![](https://i.imgur.com/Qt9lltj.png)     |      |

| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/TCLlgpa.png)     | ![](https://i.imgur.com/vsoQhqi.png)     |      |







```swift=
struct Wizard {
    
    //使用type property
  static var commonMagicalIngredients = [
    "Polyjuice Potion",
    "Eye of Haystack Needle",
    "The Force"
  ] {                                       //加入property observor
    didSet {
      print("Magical Ingredients updated! Common stock now contains \(commonMagicalIngredients)")
    }
  }
  
    //屬性
  var firstName: String {
      
      //property observor 屬性觀察
    willSet {
      print(firstName + " will be set to " + newValue)
    }
      //property observor 屬性觀察
    didSet {
      if firstName.contains(" ") {
        print("No spaces allowed! \(firstName) is not a first name. Reverting name to \(oldValue).")
        firstName = oldValue
      }
    }
  }
    //屬性
  var lastName: String
}

//實例                  給姓                   給名
var wizard = Wizard(firstName: "Gandalf", lastName: "Greyjoy")

//改姓
wizard.firstName = "Hermione"
//改名
wizard.lastName = "Kenobi"
wizard


wizard.firstName = "Merlin Rincewind"                       //No spaces allowed! Merlin Rincewind is not a first name. Reverting name to Hermione.


//type method使用
//類.函式
Wizard.commonMagicalIngredients.append("Wow-Wow Sauce")     //Magical Ingredients updated! Common stock now contains ["Polyjuice Potion", "Eye of Haystack Needle", "The Force", "Wow-Wow Sauce"]


```


# 30. Computed Properties

![](https://i.imgur.com/SgURZ1J.png)

## 程式碼
```swift=
struct Wizard {
  static var commonMagicalIngredients = [
    "Polyjuice Potion",
    "Eye of Haystack Needle",
    "The Force"
  ] {
    didSet {
      print("Magical Ingredients updated! Common stock now contains \(commonMagicalIngredients)")
    }
  }
  
  var firstName: String {
    willSet {
      print(firstName + " will be set to " + newValue)
    }
    didSet {
      if firstName.contains(" ") {
        print("No spaces allowed! \(firstName) is not a first name. Reverting name to \(oldValue).")
        firstName = oldValue
      }
    }
  }
  
  var lastName: String
  
  var fullName: String {
    get { return "\(firstName) \(lastName)" }
    set {
      let nameSubstrings = newValue.split(separator: " ")
      guard nameSubstrings.count >= 2 else {
        print("\(newValue) is not a full name.")
        return
      }
      let nameStrings = nameSubstrings.map(String.init)
      firstName = nameStrings.first!
      lastName = nameStrings.last!
    }
  }
}

var wizard = Wizard(firstName: "Gandalf", lastName: "Greyjoy")
wizard.firstName = "Hermione"                                   //Gandalf will be set to Hermione
wizard.lastName = "Kenobi"
wizard.firstName = "Merlin Rincewind"                           //Hermione will be set to Merlin Rincewind
                                                                //No spaces allowed! Merlin Rincewind is not a first name. Reverting name to Hermione.


wizard.fullName = "Severus Wenderlich"                          //Hermione will be set to Severus
```


# 31. Lazy Properties





![](https://i.imgur.com/gvdStSc.png =50%x)

| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/oby43wH.png) | ![](https://i.imgur.com/JXPfWz1.png)|      |








```swift=
struct Wizard {
  static var commonMagicalIngredients = [
    "Polyjuice Potion",
    "Eye of Haystack Needle",
    "The Force"
  ] {
    didSet {
      print("Magical Ingredients updated! Common stock now contains \(commonMagicalIngredients)")
    }
  }
  
  var firstName: String {
    willSet {
      print(firstName + " will be set to " + newValue)
    }
    didSet {
      if firstName.contains(" ") {
        print("No spaces allowed! \(firstName) is not a first name. Reverting name to \(oldValue).")
        firstName = oldValue
      }
    }
  }
  
  var lastName: String
  
  var fullName: String {
    get { return "\(firstName) \(lastName)" }
    set {
      let nameSubstrings = newValue.split(separator: " ")
      guard nameSubstrings.count >= 2 else {
        print("\(newValue) is not a full name.")
        return
      }
      let nameStrings = nameSubstrings.map(String.init)
      firstName = nameStrings.first!
      lastName = nameStrings.last!
    }
  }
  
  lazy var magicalCreature = summonMagicalCreature(summoner: fullName)
  
  init(firstName: String, lastName: String) {
    self.firstName = firstName
    self.lastName = lastName
  }
}

var wizard = Wizard(firstName: "Gandalf", lastName: "Greyjoy")
wizard.firstName = "Hermione"                                       //Gandalf will be set to Hermione
wizard.lastName = "Kenobi"
wizard.firstName = "Merlin Rincewind"                               //Hermione will be set to Merlin Rincewind
                                                                    //No spaces allowed! Merlin Rincewind is not a first name. Reverting name to Hermione.

wizard.fullName = "Severus Wenderlich"                              //Hermione will be set to Severus
print(wizard.magicalCreature)                                       //💥🧙‍♀️ The creature above was summoned by Severus Wenderlich! 🧙‍♂️💥
                                                                    //圖1
wizard.fullName = "Qui-Gon Crayskull"                               //Severus will be set to Qui-Gon
print(wizard.magicalCreature)                                       //圖2
                                                                    //💥🧙‍♀️ The creature above was summoned by Severus Wenderlich! 🧙‍♂️💥
```


| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/4JV2gID.png)| ![](https://i.imgur.com/b0ZF7T5.png)|      |

![](https://i.imgur.com/c3GY6Sn.png =50%x)


# 32. Challenge: Properties

# 33. Methods


| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/INRMqd6.png)| ![](https://i.imgur.com/ZP3DHaa.png)| Text     |


![](https://i.imgur.com/EEAxBHO.png)


## 程式碼
```swift=
enum Weekday: CaseIterable {
  case monday, tuesday, wednesday, thursday, friday, saturday, sunday

  mutating func advance(by dayCount: UInt) {        //UInt是正的數
    let indexOfToday = Weekday.allCases.firstIndex(of: self)!
    let indexOfAdvancedDay = indexOfToday + Int(dayCount)
    
    self = Weekday.allCases[indexOfAdvancedDay % Weekday.allCases.count]
  }
}

Weekday.allCases                    //[monday, tuesday, wednesday, thursday, friday, saturday, sunday]
var weekday: Weekday = .tuesday     //tuesday
weekday.advance(by: 6)              //monday

struct Time {
  var day: Weekday
  var hour: UInt

  init(day: Weekday, hour: UInt = 0) {
    self.day = day
    self.hour = hour
  }
  
  mutating func advance(byHours hourCount: UInt) {
    self = self.advanced(byHours: hourCount)
  }
  
  func advanced(byHours hourCount: UInt) -> Time {
    let (dayCount, hour) = (self.hour + hourCount).quotientAndRemainder(dividingBy: 24)
    var time = self
    time.day.advance(by: dayCount)
    time.hour = hour
    return time
  }
}

let time = Time(day: .monday)
var advancedTime = time.advanced(byHours: 24 * 3 + 5)       //thursday     hour 5
advancedTime.advance(byHours: 6)                            //thursday      hour 11

enum Mathematics {
  static func getLength(x: Double, y: Double) -> Double {
    return (x * x + y * y).squareRoot()
  }
}

Mathematics.getLength(x: 3, y: 4)                           //5.0
```

# 34. Challenge: Methods

# 35. Computed Properties or Methods?


| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/XEjhkGJ.png)| ![](https://i.imgur.com/WIEgcQG.png)|      |

![](https://i.imgur.com/3hljwjX.png =50%x)




# 36. Conclusion



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/Gso2i0V.png) | ![](https://i.imgur.com/ivp9dw7.png)|      |






[Part5] Protocols & Inheritance
===

# 37. Introduction


| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/PRyTz89.png)| ![](https://i.imgur.com/Nb6NFTH.png)|      |



# 38. Inheritance


| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/Gj2QZzm.png)     | ![](https://i.imgur.com/X1lxqpa.png)     |     |



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/ORwkRh1.png)     | ![](https://i.imgur.com/5LsqYDm.png)     |      |

![](https://i.imgur.com/ApalOB9.png =50%x)

```swift=

//分數    類struct
struct Grade {
  var letter: Character
  var points: Double
  var credits: Double
}


//人類
class Person {
  var firstName: String
  var lastName: String
  
  init(firstName: String, lastName: String) {
    self.firstName = firstName
    self.lastName = lastName
  }
}

//學生類    繼承    人類
class Student: Person {
  var grades: [Grade] = []
}

//樂團成員學校    繼承    學生類
class SchoolBandMember: Student {
  var minimumPracticeTime = 2
}

//運動員學生    繼承    學生類
class StudentAthlete: Student {
  override var grades: [Grade] {
    didSet {
      if !isEligible {
        print("It's time to study!")
      }
    }
  }
  var isEligible: Bool {
    return grades.filter { $0.letter == "F" } .count < 3
  }
}


let jon = Person(firstName: "Jon", lastName: "Snon")                //人類的實例
let jane = Student(firstName: "Jane", lastName: "Snane")            //學生類的實例
let jessy = SchoolBandMember(firstName: "Jessy", lastName: "Catterwaul") //樂團學校成員類的實例
let marty = StudentAthlete(firstName: "Marty", lastName: "McWolf")    //運動員學生的實例

let array = [jane, jessy, marty]    //學生類 或 繼承於學生類的實例 陣列

let student = marty as Student            //Upcasting
let athlete = student as! StudentAthlete  //Downcasting   100%確定會成功，不然會死機



let utterFailureGrade = Grade(letter: "F", points: 0, credits: 0)    //分數類的實例
athlete.grades.append(utterFailureGrade)    
athlete.grades.append(utterFailureGrade)
athlete.grades.append(utterFailureGrade)

//方法    屬性繼承於學生類
func getEveningActivity(student: Student) -> String {
  if let bandMember = student as? SchoolBandMember {
    return "Practicing for at least \(bandMember.minimumPracticeTime)"
  } else {
    return "Hitting the books!"
  }
}

//呼叫方法
getEveningActivity(student: jessy)    //參數帶學生樂團的實例
getEveningActivity(student: jane)    //參數帶學生類的實例


//分數類的實例
let historyGrade = Grade(letter: "B", points: 9, credits: 3)
jane.grades.append(historyGrade)    //學生類的實例 屬性加上
```

# 39. Challenge: Inheritance
```swift=
class Animal {
  func speak() { }
}

class WildAnimal: Animal {
  let isPoisonous: Bool
  
  init(isPoisonous: Bool) {
    self.isPoisonous = isPoisonous
  }
}

class Pet: Animal {
  let name: String
  
  init(name: String) {
    self.name = name
  }
  
  func play() {
    print("Playtime! ... now naptime 💤")
  }
  
  override func speak() {
    print("Hi I'm \(name)! I am cute. Pet me!")
  }
}

class Cat: Pet {
  override func speak() {
    print("I can has Cheezburger?")
  }
}

```


# 40. Initializers



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/Hl2dYSL.png)| ![](https://i.imgur.com/7c7hpJo.png)|      |



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/1l6iTdv.png)
     | Text     |      |



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/AUsUeAz.png)| ![](https://i.imgur.com/a1xn6zY.png)
|      |




```swift=
class Person {
  var firstName: String
  var lastName: String
  
  required init(firstName: String, lastName: String) {
    self.firstName = firstName
    self.lastName = lastName
  }
}

//學生類    繼承 人類
class Student: Person {
  var grades: [String] = []
  
  convenience init(transfer: Student) {
    self.init(firstName: transfer.firstName, lastName: transfer.lastName)
    grades = transfer.grades
  }
}

//運動員學生    繼承    學生類
class StudentAthlete: Student {
  var sports: [String]
  
  required convenience init(firstName: String, lastName: String) {
    self.init(firstName: firstName, lastName: lastName, sports: [])
  }
  
  convenience init(transfer: StudentAthlete) {
    self.init(firstName: transfer.firstName, lastName: transfer.lastName, sports: transfer.sports)
    grades = transfer.grades
  }
  
  init(firstName: String, lastName: String, sports: [String]) {
    self.sports = sports
    super.init(firstName: firstName, lastName: lastName)
  }
}

//運動員學生的實例
let rudy = StudentAthlete(firstName: "Daniel", lastName: "Ruettiger", sports: ["Foosball"])

StudentAthlete(firstName: "Bernie", lastName: "Kosar")

StudentAthlete(transfer: rudy).sports
```


# 41. Challenge: Initializers

Challenge 1 😃

Create a class named Animal that has…

a single stored property named name, that is a String
a required initializer that takes name as a parameter
a function speak() that does nothing.

```swift=
class Animal {
  var name: String
  
  func speak() { }
  
  required init(name: String) {
    self.name = name
  }
}
```

Create a class named Dog that…

inherits from Animal
has a property that stores how many tricks it has learned
implements the required initializer, defaulting the trick count to 0, and calling speak() at the end
overrides the function speak() to greet you and says its name


```swift=
class Dog: Animal {
  var tricksLearnedCount: Int
  
  convenience required init(name: String) {
    self.init(name: name, tricksLearnedCount: 0)
  }
  
  init(name: String, tricksLearnedCount: Int) {
    self.tricksLearnedCount = tricksLearnedCount
    super.init(name: name)
    speak()
  }
  
  convenience init(tricksLearnedCount: Int = .max) {
    self.init(name: "Tramp", tricksLearnedCount: tricksLearnedCount)
  }
  
  override func speak() {
    print("Bow wow! My name is \(name)!")
  }
}

Dog(name: "Shadow")
Dog(name: "Chance", tricksLearnedCount: 3)
Dog().tricksLearnedCount
```

Add a second (non-required) initializer to Dog that takes both the name and numTricksLearned as parameters. Then call this initializer from the required initializer.


Add a convenience initializer to Dog that defaults the dog's name to your favorite dog's name, with however many tricks the dog has learned.



# 42. Protocols



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/Tv9Hm4f.png)| ![](https://i.imgur.com/MDlF61X.png)
|      |



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/PpOxvtF.png)| ![](https://i.imgur.com/R0BXi1l.png)|      |

![](https://i.imgur.com/lnadYhB.png)


## 程式碼
```swift=
//動物協定
protocol Animal {
  var name: String { get }      //let 改 var 括號裡面加上get

  init(name: String)

  func speak()
}

//狗類 繼承 動物協定
class Dog: Animal {
  let name: String             //因為動物類屬性有name
  var tricksLearnedCount: Int
  
  init(name: String, tricksLearnedCount: Int) {
    self.tricksLearnedCount = tricksLearnedCount
    self.name = name
  }
  
  convenience required init(name: String) {
    self.init(name: name, tricksLearnedCount: 0)
  }
  
  func speak() {
    print("Bow wow! My name is \(name)!")
  }
}

//貓類 繼承 動物協定
class Cat: Animal {
  let name: String          //因為動物類屬性有name
  
  required init(name: String) {
    self.name = name
  }
  
  func speak() {
    print("My name is \(name). Please leave me alone. I must look at this wall.")
  }
}

//動物協定陣列的實例
let animals: [Animal] = [Dog(name: "Fang"), Cat(name: "Mr. Midnight")]  //[{name "Fang", tricksLearnedCount 0}, {name "Mr. Midnight"}]


for animal in animals {
  animal.speak()
}

//Bow wow! My name is Fang!
//My name is Mr. Midnight. Please leave me alone. I must look at this wall.


```

# 43. Protocols & Extensions



| Column 1 | Column 2 | |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/AegEdYh.png)| ![](https://i.imgur.com/BLlWedf.png)|  |




| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/rTUNoFO.png)| ![](https://i.imgur.com/7TLrDWH.png)|  |





| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/HEQBMUP.png)| ![](https://i.imgur.com/LBDAJUA.png)|   |



## 程式碼
```swift=
//動物類
protocol Animal {
  var name: String { get }

  init(name: String)

  func speak()
}


//延伸 動物協定
extension Animal {
    
    //改變 說話方法
  func speak() {
    print("I'm an animal!")
  }
}

protocol Aloof {
  var name: String { get }
}


//延伸  Aloof協定
extension Aloof {
    
    //增加  屬性問好
  var greeting: String {
    "My name is \(name). Please leave me alone."
  }
}

protocol AloofAnimal: Aloof, Animal { }


//延伸    AloofAnimal協定
extension AloofAnimal {
    
    //改變 說話方法
  func speak() {
    print("\(greeting) I must look at this wall.")
  }
}

//狗類 繼承 動物類
class Dog: Animal {
  let name: String
  var tricksLearnedCount: Int
  
  init(name: String, tricksLearnedCount: Int) {
    self.tricksLearnedCount = tricksLearnedCount
    self.name = name
  }
  
  convenience required init(name: String) {
    self.init(name: name, tricksLearnedCount: 0)
  }
  
  func speak() {
    print("Bow wow! My name is \(name)!")
  }
}


//貓類 繼承 動物類
class Cat {
  let name: String
  
  required init(name: String) {
    self.name = name
  }
}


//延伸 貓類 繼承AloofAnimal類
extension Cat: AloofAnimal {
  func speak() {
    print(greeting + "Meow!")
  }
}

//動物類實例
let animals: [Animal] = [Dog(name: "Fang"), Cat(name: "Mr. Midnight")]
for animal in animals {
  animal.speak()
}

//Bow wow! My name is Fang!
//My name is Mr. Midnight. Please leave me alone.Meow!






//: Extensions!

// --------------------------------
func isEven(_ value: Int) -> Bool {
  value % 2 == 0
}
func isOdd(_ value: Int) -> Bool {
  (value + 1) % 2 == 0
}
// --------------------------------


//延伸 Int類功能
extension Int {
  var isEven: Bool {
    self % 2 == 0
  }
  var isOdd: Bool {
    (self + 1) % 2 == 0
  }
}

5.isOdd         //true
5.isEven        //false


//延伸 Numeric類功能
extension Numeric {
  var squared: Self { self * self }
}

5.squared       //25
5.5.squared     //30.25


//: More Extensions!

// --------------------------------
//Weekday類
enum Weekday: CaseIterable {
  case monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

//Time類
struct Time {
  var day: Weekday = .monday
  var hour: UInt = 0
}

//延伸 Time類
extension Time {
  init(day: Weekday) {
    self.day = day
  }
}
// --------------------------------

Time(day: .friday, hour: 17)
Time()
Time(day: .wednesday)

```


# 44. Challenge: Protocols

# 45. Value vs. Reference Types



| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/eGthcZt.png)| ![](https://i.imgur.com/G19ran7.png)|   |




|  啞鈴 | 跑鞋 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/JBkBvoy.jpg)| ![](https://i.imgur.com/cqqchvv.jpg)| Text     |




| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/ZUnrmB7.png)| ![](https://i.imgur.com/PkndiOQ.png)|      |




| Column 1 | Column 2 |   |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/KpRX5b0.png)| ![](https://i.imgur.com/pEJaL65.png)|      |




| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/ealyvMi.png)| ![](https://i.imgur.com/C8YVkIj.png)|   |



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/Ni45d54.png)| ![](https://i.imgur.com/uQZMDqz.png)| |



| Column 1 | Column 2 |  |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/pBNgsz6.png)     | ![](https://i.imgur.com/63NNvLH.png)|      |


# 46. Conclusion



| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| ![](https://i.imgur.com/Eg0Dtb5.png)| ![](https://i.imgur.com/VRfT9zM.png)| ![](https://i.imgur.com/wiwRDIQ.png)|



###### tags: `[Kodeco IOS]`