---
# System prepended metadata

title: Swift - 判斷、集合、迴圈
tags: [iOS]

---

---
title: 'Swift - 判斷、集合、迴圈'
disqus: kyleAlien
---

Swift - 判斷、集合、迴圈
===

## Overview of Content

[TOC]

## Swift 表達結構

在這裡我們要建立幾個名詞的概念，陳述式、表達式、變數、常數... 等等，它們都與程式密切的關係

:::info
這些名詞可以讓我們更好的分析、認識程式，但注意不要糾結於這些名詞，這些名詞可能會因為語言不同而有不同的描述方式
:::

### Swift 程式 - 基本組件

* Swift 程式是由各種不同元素組成，其主要組成元素如下（請配合以下範例一起對照）
    
    | 元素名 | 特性 | 補充 |
    | - | - | - |
    | 變數（variable） | 變數是一種可以在運行時改變的數據 | - |
    | 常數（constant） | 常數在運行時不可修改 | 設定後就永遠不可修改 |
    | 字面值（literal） | 字面值就是有意義的 “數據”，這些數據有各種不同型態（String, Bool... 等等） | - |
    | 型態（type） | 標註變數、常數的類型，說明要如何解釋這個數據 | - |
    | 陳述式（statement） | 程式準備執行的動作 | for-in, if... 等等，會有許多不同特性 |
    | 表達式（expression） | 負責回傳結果值 | - |
    | 宣告（declaration） | 負責將一個新的名字（使用者定義）導入程式 | 可以宣告變數、常數、函數、結構 ... 等等 |

    ```swift=
    // *變數*
    // 變數格式：var <變數名> : <型態> = <字面值>
    // 對照：變數名    myString
    //      型態     String
    //      字面值   "Hello world" 
    var myString : String = "Hello world"    
    
    // *變數*
    var isShowing : Bool = true

    // *常數*
    // 常數格式：var <變數名> : <型態> = <字面值>
    // 對照：變數名    NAME
    //      型態     String（語字自動推導）
    //      字面值   "Hello world" 
    let NAME = "Kyle"

    // *陳述式*（判斷）
    if isShowing {
        // *陳述式*（循環迴圈）
        for tmp in 1...5 {
            // 函數
            print("\(myString): \(tmp)")
        }
    }

    // *表達式* (最終輸出一個結果)
    myString += ", Yoyo"

    // 函數
    print("\(NAME), \(myString)")
    ```
    > 執行結果
    > 
    > ![](https://i.imgur.com/tZnsNqT.png)

### 運算子 Operator

* 建構組件 運算子 (Operator) 在每個程式語言中都相當重要，可以透過它檢查、修改資料；它的通常有兩種方式表達

    * **符號**：`+`、`-`、`*`... 等等
    
    * **片語**：`inc`、`dec` ... 等等（通常用於運算符重載，每個運算符都有對應的片語，可以參考 ）
        > 這裡不說明片語

    * 運算子分類：如下表

        | 分類 | 說明 | 舉例 |
        | -------- | -------- | -------- |
        | 一元 (unary) | 運算一個數值 | -1 |
        | 二元 (binary) | 運算兩個值 | 1 + 2 |
        | 三元 (ternary) | 先判斷再決定 | value ? 1 : 666 |

        :::info
        * 運算子運作的 Scope
        
            上面範例來說都是數字運算，然而運算子不只可以運作在數字上 (只是常見)；它還可以運作在字串，甚至 **只要符合某些條件也可以運作在物件上**
        :::

* 下表為幾個常見的數學運算子
    
    | 運算子 | 說明 | 舉例 |
    | - | - | - |
    | + | 加法 | 1 + 2 = 3 |
    | - | 減法 | 10 - 8 = 2 |
    | * | 乘法 | 11 * 3 = 33 |
    | / | 除法 | 6 / 3 = 2 |
    | % | 取模 (取餘數) | 10 / 7 = 3 |

    ```swift=
    print("1 + 2 = \(1 + 2)")

    print("10 - 8 = \(10 - 8)")

    print("11 * 3 = \(11 * 3)")

    print("6 / 3 = \(6 / 3)")

    print("10 % 7 = \(10 % 7)")
    ```
    > ![](https://i.imgur.com/BK3pfCk.png)


    :::success
    * **表達式（expression）**
        
        運算子最終都會產生一個值，對於有最終產值的行為，我們都稱為表達式（expression）
    :::
    
    :::warning
    * **空格不可混用**
        
        Swift 中空格與運算子之間不可混用否則會編譯不過
        
        ```swift=
        var result = 0
        // Error
        result = 12 /4
        result = 12/ 4

        // OK
        result = 12 / 4
        result = 12/4
        ```
    :::

* 等號 `=` 也是運算子（**指定運算子**），所有出現在 `=` 後的值都是 **字面值（`literal`）**，這個字面值不只是數字，也可以是其他數據


### Swift 基礎型態

* **++型態++** 對於程式語言是一種強硬的設計！但同時也保證其安全性；在 Swift 中有以下方式可以定義型態
    
    1. 宣告變數時，直接指定型態
    
        ```swift=
        var myVariable1: Int = 123
        ```
    
    2. 宣告變數時，給定數值，讓編譯器自動推導

        ```swift=
        var myVariable2 = 77.0
        ```

    3. 宣告變數，並指定型態，延遲指定變數

        ```swift=
        var myVariable3: String

        myVariable3 = "iOS"
        ```
        
        :::danger
        * 延遲指定注意
            
            1. 這裡雖然延遲指定變數，但是在使用該變數時編譯器會判斷你是否有指定變數，如果沒指定會導致編譯不過
        
                > ![](https://i.imgur.com/IyJXCi9.png)
            
            2. 延遲指定變數，之後要指定也要是相同類型才能指定
                
                > ![](https://i.imgur.com/pX2vJzT.png)

        :::

* Swift 的基礎型態包括：
    
    > Swift 還提供了許多高級型態，例如陣列、字典、元組等，可以更方便地處理複雜的數據結構

    1. **整數型態**：用於表示整數數值，包括 `Int`、`UInt8`、`UInt16`、`UInt32`、`UInt64`、`Int8`、`Int16`、`Int32`、`Int64`

        ```swift=
        var myInt: Int = 10
        ```
        
        :::info
        * **Int 怎麼分這麼多不同型態**？
            
            我們最常用的 `Int` 型態會依據我們使用裝置的硬體（CPU 總線）來決定該型態的大小（可能 32 or 64 bit）
            
            而其他型態則是我們清楚指明要使用的類型，其可能包括有符號 (Signed)、無符號 (Unsignd)的不同大小
        :::
    
    2. **浮點型態**：用於表示浮點數值，包括 `Float`、`Double`；**swift 預設型態為 Double**
        
       > 我們可以透過 type 來判斷其類型

        ```kotlin=
        var myFloat : Float = 10.0
        print(type(of: myFloat))

        var myDobule : Double = 10.0
        print(type(of: myDobule))

        print("Default: \(type(of: 10.0))")
        ```
        > ![](https://i.imgur.com/vizRsiD.png)    
    
    3. **Bool 布林型態**：用於表示邏輯值，包括 `true` 和 `false`

        ```swift=
        var myBool : Bool = true
        var myBool_1 : Bool = false
        ```
    
    4. **String 字符串型態**：用於表示文字，包括 `String`

        ```swift=
        var myString: String = "Hello World"
        ```
        
    5. **Character 字符型態**：用於表示單個字符，包括 `Character`；Swift 不使用這個符號 `'` 描述單個字符

        ```swift=
        var myChar : Character = "A"
        ```
    
    6. **選擇型態**：用於表示一個值或者沒有值（也就是可以沒有值的意思），包括 `Optional`

        ```swift=
        var myOptional : Optional = "ABC"
        // 非 Optional 型態不可設定為 nil
        myOptional = nil
        ```

        > Optional 型態的細節之後再說明

## 集合

Swift 有一系列用於儲存數據的型態（類型），這些型態就稱為 **集合**，其主要集合型態為 ^1.^ Array, ^2.^ Set, ^3.^ Dictionary 它們的特性都不相同

:::warning
集合中可以有多個數據，但 **集合中的數據必須要相同類型**
:::

### Array - 順序性

* **Array（陣列）的特性**：**有順序性、數據可以重複、透索引值取值**；其創建方式如下

    > Array 又稱之為陣列

    :::success
    索引值從 0 開始算
    :::

    * 數據格式：[ <數據>* ]
    
        ```swift=
        let myArray : Array = [1, 2, 9, 3, 7, 9]

        // 其型態也可以寫出來
        let myArray2 : [Int] = [1, 2, 9, 3, 7, 9]
        ```
        
    * **Array 常用 API**：

        | 功能 | API |
        | - | - |
        | Array 當前數據數量 | count |
        | Array 是否為空 | isEmpty |
        | 新數據加到後方 | append(value) |
        | 新數據插入指定位置 | insert(value, index) |
        | 移除指定位置數據 | remove(index) |
        
        ```swift=
        var myArray : [Int] = [1, 2, 3]

        print("index of 0: \(myArray[0])")

        myArray.append(100)
        print("index of 3: \(myArray[3])")

        myArray.insert(99, at: 3)

        print("index of 3: \(myArray[3])")


        if !myArray.isEmpty {
            print("Current count, \(myArray.count)")
        }

        print("Before remove, index of 0: \(myArray[0])")
        myArray.remove(at: 0)
        print("After remove, index of 0: \(myArray[0])")
        ```
        > ![](https://i.imgur.com/gWqu8vH.png)

### Set - 不可重複性

* **Set 的特性**：**無序性、數據唯一、無法透過索引取值**；其創建方式如下
    
    
    * 數據格式：
        
        1. Set([ <數據>* ])

            ```swift=
            let mySet1 = Set([3, 3, 1, 4, 7, 9, 1])
            ```

        2. 宣告類型 Set = [ <數據>* ]

            ```swift=
            let mySet2 : Set = [3, 3, 1, 4, 7, 9, 1]
            ```
    * **Set 常用 API**：

        |       API       | 功能                     |
        |:---------------| ------------------------ |
        |      count      | Array 當前數據數量       |
        |     isEmpty     | Array 是否為空           |
        |  insert(value)  | 插入新數據               |
        | contains(value) | 判斷集合內是否有某個數據 |
        |  remove(index)  | 移除指定數據             |

        ```swift=
        var mySet : Set = [9, 2, 3, 5, 5, 6, 1, 5]

        mySet.insert(8)

        if mySet.contains(9) {
            mySet.remove(9)
        }

        if !mySet.isEmpty {
            print("Current count, \(mySet.count)")

            for item in mySet {
                print("Set item: \(item)")
            }
        }
        ```
        :::warning
        1. 從結果可以發現，Set 不會儲存重複相同的數據
            
            > 以上 5 雖然重複，不過它最終在 Set 中只有一個

        2. Set 集合是無法直接取得數據的，所以這邊使用 for 循環遍歷集合
        :::
        
        > ![](https://i.imgur.com/Bf30fRB.png)


### Dictionary - 鍵值

* **Dictionary 的特性**：**無序性、數據透過 key/Value 的方式儲存**；其創建方式如下

    * 數據格式：[ <Key : Value\>* ]

        ```swift=
        let myDictionary = [ 1 : "A", 2 : "B", 3 : "C", 4 : "D" ]

        let myDictionary2: [Int: String] = [ 1 : "A", 2 : "B", 3 : "C", 4 : "D" ]
        ```
        
        :::info
        * 可以指定一個空 Dictionary，不過要先宣告類型，否則編譯器會不知道該變數的類型

            ```swift=
            let emptyDictionary : [String: Float] = [:]
            ```
        :::
      
        
    * **Dictionary 常用 API**：

        | 功能 | API |
        | - | - |
        |      count      | Dictionary 當前數據數量       |
        |     isEmpty     | Dictionary 是否為空           |
        | updateValue(Value, Key) | 更新指定 Key 的數據 |
        | [Key] = Value | 更新指定 Key 的數據 |
        | removeValue(key) | 用 Key 來移除 Dictionary 中的數據 |
        
        
        ```swift=
        var myDictionary3 = [ 1 : "A", 2 : "B", 3 : "C", 4 : "D" ]


        if !myDictionary3.isEmpty {
            print("Count: \(myDictionary.count)")
        }

        myDictionary3.updateValue("AAA", forKey: 1)

        print("The 1 value is \(myDictionary3[1])")

        myDictionary3[1] = "ABCDEFG"

        print("The 1 value is \(myDictionary3[1])")


        myDictionary3.removeValue(forKey: 2)

        print("The 2 is \(myDictionary3[2])")
        ```
        
        > ![](https://i.imgur.com/9ACZbq9.png)

### Tuple 集合

* Tuple (元組) 集合可以讓多個值儲存在單一變數、常數中，其中的元素可以修改，而不會像有陣列之類的負擔
    
    > 並且它可以特別指定元素的名稱

    :::info
    * 這裡的負擔是指啥？

        * Array 通常需要指定大小或容量，並且需要連續的記憶體空間來存儲元素。當陣列的大小需要改變時，可能需要重新分配記憶體空間，把現有的元素拷貝到新的位置上，這樣的操作需要額外的時間和資源

        * 相較之下，Tuple 可以讓多個值以 **有序** 的方式存在單一變數、常數中，^1.^ 不需要指定容量，也 ^2.^ 不需要連續的記憶體空間
        
        因此，使用元組可以減少記憶體的使用，並且在運行時不需要額外的內存分配和拷貝操作，因此可以更加高效
    :::
        
    * Tuple 可以指定 & 不指定其元素的名稱

        ```swift=
        var myTuple = (10, 20)
        
        // tuple 元素可修改
        myTuple.0 = 55

        // 不指定時按照 index 取得數據
        print("my tuple , 0: \(myTuple.0)")
        print("my tuple , 1: \(myTuple.1)")

        // 可以指定元素名稱
        var myTuple2 = (a: 100, 200)

        // 按照元素名稱取得數據
        print("my tuple 2, a: \(myTuple2.a)")
        // 沒指定的話，就按照 index 取得
        print("my tuple 2, 1: \(myTuple2.1)")
        ```

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

## 陳述式 - Expression

上面我們有提到陳述式（Expression）是一個程式語言的基本組成，它可以幫你進行迴圈、判斷... 等等功能；

:::success
這種控制程式運行的手法常被稱之為：控制流、結構化
:::

* swift 常用 Expression 如下

    1. 判斷條件：`if`, `switch`

    2. 迴圈：`for`, `for-in`, `while` ,`repeat-while`


### 判斷條件 - if 

* 使用 `if` 的前提是，真假判斷（Bool 表達式）也就是說要有一個 True、False 的輸出，才能使用 `if` 判斷；其格式如下

    ```swift=
    if(真假判斷) {
        // 成立後執行的程式
    } else {
        // 不成立後執行的程式
    }

    // 使用空格就可以省略 `()`---------------------------

    if 真假判斷 {
        // 成立後執行的程式
    } else {
        // 不成立後執行的程式
    }
    ```

    * 使用範例：

        ```swift=
        var showMsg: Bool = true

        if showMsg {
            print("Hello World")
        } else {
            print("What?")
        }
        ```
        > ![](https://i.imgur.com/raCjkIB.png)

* 同一個 `if` 判斷，可以用 `else if` 增加更多的條件判斷，也可以讓其他人明白該判斷相關的條件不止一個

    ```swift=
    var mylist = [1, 2, 3]

    if mylist.isEmpty {
        print("I get empty list.")

    } else if mylist.count == 1 {
        print("I get the list, the size is 1.")

    } else if mylist.count == 2 {
        print("I get the list, the size is 2.")

    } else if mylist.count == 3 {
        print("I get the list, the size is 3.")

    } else {
        print("I get the big size of list.")
    }
    ```
    > ![](https://i.imgur.com/S8YCfll.png)



### 判斷條件 - switch 

* 使用 `switch` 同樣是判斷條件，但是它會把自動把需要判斷的數據帶入每個不同的條件狀況 (`case`)，看起來會更加的簡潔；其格式如下

    ```swift=
    switch(數值) {
        
    case 條件狀況:
        // 符合條件狀況則執行這
        
    default:
        // 以上狀況皆不符合則執行這
    }


    // 使用空格就 switch 可以省略 `()`---------------------------

    switch 數值 {
        
    case 條件狀況:
        // 符合條件狀況則執行這
        
    default:
        // 以上狀況皆不符合則執行這
    }
    ```

    :::success
    * `if` vs. `switch` 使用

        兩者沒有絕對要使用哪一個（基本上憑經驗判斷），但可以注意到的是 `if` 可以取多種方案多個判斷，而 `switch` 更針對一種方案多個判斷
        > switch 更指定，長遠來看更好維護
    :::
    
    * 使用範例：

        ```swift=
        var mylist = [1, 2]

        // 指定要判斷的方案
        switch mylist.count {
        // 以下在各種 case 中判斷
        case 0:
           print("I get empty list.")

        case 1:
            print("I get the list, the size is 1.")

        case 2:
            print("I get the list, the size is 2.")

        case 3:
            print("I get the list, the size is 3.")

        default:
            print("I get the big size of list.")
        }
        ```
        
        > ![](https://i.imgur.com/xaM7Zx3.png)

:::warning
* **Swift 與其他語言的不同**：
    
    它仍然有 `break`、`continue`，不過在 case 自然結束時不需要添加，只有在需要中途跳出時才需添加
    
    ```swift=
    switch mylist.count {
    case 0:
       print("I get empty list.")

    case 1, 2:
        if mylist[0] == 1 {
            print("list element of 0 if 1")
            // 跳出該 case
            break
        }

        // 不會被執行到
        print("I get the list!")

    default:
        print("I get the big size of list.")
    }
    ```
    > ![](https://i.imgur.com/ECkoSKb.png)

:::

### 迴圈 - for-in / foreach

* `for-in` 陳述式用來遍歷集合（Collection）數據，其格式如下

    ```swift=
    // 遍歷 range 時，`constains` 數值就會一直更新
    for constains in range {
        // other code
    }
    ```
    
* `for-in` 使用範例

    ```swift=
    let array = [1, 2, 55, 11, 88]

    for tmp in array {
        print("Current value = \(tmp)")
    }
    ```
    > ![](https://i.imgur.com/RsWuY0P.png)

    :::info
    * `foreach` 是集合的一種 API 可以簡化 `for-in`，使用方式如下：

        ```swift=
        let array = [1, 2, 55, 11, 88]

        array.forEach {
            // 取直改成使用 `$0`
            print("Current value = \($0)")
        }
        ```
        > 輸出同上
    :::
    
    :::success
    
    * swift 沒辦法自己控制回圈的 index，所以要逆向搜尋的話就需要使用 `resversed()` 方法
    
        ```swift=
        for j in (0...times).reversed() {
            // do nothing
        }
        ```
    :::


### 迴圈 - while / repeat-while

* `while` 陳述式同樣可以用來遍歷數據，通常用使用在不清楚回圈需循環幾次時的狀況；其格式如下

    ```swift=
    // 每次循環都會回頭判斷 condition
    // 若 condition 為 false 則結束循環，反知繼續循環
    while condition {
        // other code
    }
    ```

    * `while` 使用範例

        ```swift=
        var value = 1

        while value < 100 {
            print("Before value: \(value)")

            value = value * 5

            print("After value: \(value)\n")
        }

        print("Final value: \(value)")
        ```
        > ![](https://i.imgur.com/V3EzKjs.png)

* `repeat-while` 與 `while` 差不多，但是 `repeat-while` 的判斷放置到執行程式之後；其格式如下


    ```swift=
    var value = 1
    var updating = true

    repeat {

        if value < 100 {
            print("Before value: \(value)")

            value = value * 5

            print("After value: \(value)\n")
        } else {
            updating = false
        }


    } while updating

    print("Final value: \(value)")
    ```

    :::warning
    * `while`, `repeat-while` 使用起來要特別注意，若是沒有修改條件（condition）則會造成無限迴圈
    :::


## 其他


### 型態別名 - typealias

* 首先，型態別名（type alias）只會對該型態取一個別名，並不會修改該型態的特性，**它可以加強程式的可讀性！** 其格式如下

    ```swift=
    typealias <別名> = <型態>
    ```
    
    * 範例：

        ```swift=
        typealias Celsuis = Int
        typealias Fahrenheit = Int

        var tempC : Celsuis = 35
        var tempF : Fahrenheit

        tempF = (tempC * 9 / 5) + 32

        print("Celsuis = \(tempC), Fahrenheit = \(tempF)")
        ```
        > ![](https://i.imgur.com/HtD3BQj.png)

        :::warning
        * 過多的別名可能會導致程式的可讀性降低，最好是將別名限制在某個區域範圍內使用
        :::

### 範疇運算子

* Swift 有提供幾個運算子（符號）來幫助我們簡單定義一組範圍；見下表

    | 名稱 | 運算子（符號格式） | 重點 |
    | - | - | - |
    | 封閉範疇運算子 | num_1...num_2 | 預設 `<=` (左開又開) |
    | 半開放範圍運算子 | num_1..<num_2 | 指定 `<` (左開右閉) |
    | 單邊範圍運算子 | num_1... | 從 >= num_1 開始不限定最大 |
    | 單邊範圍運算子 | ...num_2 | 不限最最小直到 <= num_2 |

    ```swift=
    let hasLess = 10...
    print("hasLess, contains 10: \(hasLess.contains(10))")
    print("hasLess, contains 11: \(hasLess.contains(11))")


    let hasMax = ...100
    print("hasMax, contains 100: \(hasMax.contains(100))")
    print("hasMax, contains 101: \(hasMax.contains(101))")

    for i in 3...5 {
        print("hasRange, item: \(i)")
    }

    let range = 10..<20
    print("range, contains 19: \(range.contains(19))")
    print("range, contains 20: \(range.contains(20))")
    ```

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

* 範疇運算子也可以用在 switch 陳述式中

    ```swift=
    let value = 19

    switch value {
    case 0...10:
        print("In range 0...10")

    case 10...20:
        print("In range 10...20")
    default:
        print("Value in other range.")
    }
    ```

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


## Appendix & FAQ

:::info
:::

###### tags: `iOS`
