iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
1

流程控制

在程式執行時,我們可以透過if判斷、guard與switch case來改變程式執行流程。

if判斷

if判斷式基本有三種變化

// 第一種
if number == 1 {

}

// 第二種
if number == 1 {

} else {

}

// 第三種
if number == 1 {

} else if number == 2 {

}

如果if後面的判斷式包含了兩個以上的邏輯判斷,可用以下符號作邏輯運算

  • || 代表 or
  • && 代表 and (也可以用逗號「,」)
  • ! 代表 not

Guard

guard 語句,類似於 if 語句,使用 guard 語句來要求一個條件必須是真才能繼續執行後面的程式碼。與 if 語句不同, guard 語句總是有一個 else 分句—— else 分句裡的代碼會在條件不為真的時候執行。
雖然這也可以靠if else來完成,但是guard有「把守、確保」的意思,如果我們要確保某些事情發生或不發生,使用guard讓程式碼的可讀性可以更加明暸。

func securityCheck(someone: String) {
    guard someone == "have a key" else {
        print("You can't pass.")
        return
    }
    print("open the door")
}
var Charlie = "have a key"
securityCheck(someone: Charlie) //印出"open the door"

上例可以清楚解釋 「當某個人有鑰匙的時候才開門」

Switch Case

switch case的用法如下,如果case裡有程式碼的話,break可以省略,也就是說:

  1. case裡不可以沒有程式碼,如果確定沒有需要執行的內容,需要加入break
  2. 不會從每個case的末尾貫穿到下一個case裡。亦即整個 switch 語句會在匹配到第一個 case執行完畢後退出
let city = "TNN"

switch city {
case "TPE":
    print("Taipei")
case "TXG":
    print("Taichung")
case "TNN":
    print("Tainan")	//匹配成功,印出"Tainan"後跳離switch
default:
    print("the other city")
} 

除此之外,也可以在case中宣告暫時性的常數或變數,並用where語句來做條件限制,Ex:

//判別point是否在x=y或x=-y線上
let point = (2,4)

switch point {
    case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
    case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
    case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}

Closures (閉包)

主要是將一個程式區段當成函數的參數或是類別的屬性來傳遞,Ex:

func inc (value: Int) -> Int {
    return value + 1
}

func dec (value: Int) -> Int {
    return value - 1
}

func f(_ value: Int, op: (Int) -> Int) -> Int {
    return op(value)
}
f(10, op: inc)  //印出11
f(20, op: dec)  //印出19

先來看三個實作的函數

  1. 函數名稱 inc,輸入值 value是Int型態,回傳值是Int型態,執行內容是value +1
  2. 函數名稱 dec,輸入值 value是Int型態,回傳值是Int型態,執行內容是value -1
  3. 函數名稱 f,輸入值有兩個:value是Int型態,另一個op是(Int)->Int型態,回傳值是Int型態,執行內容是op(value)。

這邊再把op的資料型態拿出來看一下(Int)->Int,也就是op本身也要是一個函數,而且該函數必須要符合『輸入值是Int型態,輸出值是Int型態』,剛好我們實作的inc、dec恰好符合這個形態,因此op的後面可以直接引用這兩個函數。

如果我們事先沒有給予inc或是dec一個函數名稱,而是將整個函數內容寫進op裡面,這種語法就稱為 inline closure,EX:

let n = f(5, op: {(value) -> Int in return value * value})
print(n) //印出 25

op位置的closure可以放到f()函數的最後面,這樣的語法就稱為trailing closure,EX:

let n = f(5) {(value) -> Int in return value * value}
print(n) //印出 25

Swift允許使用 $0、$1、$2來代替closure中的參數名稱,而且回傳值可以自動判定,因此f()函數中的inline closure可以簡寫成:

let n = f(5) {
	return $0 * $0
}
print(n) //印出 25

類別(Classes), 屬性(Properties), 函數(Functions)

類別(Classes)

Swift中最簡單的類別寫法如下,其中init()函數為類別實體化時會呼叫的函數,若類別不需要初始化,這個函數可以省略不寫。

class someClass: NSObject {
	override init()	{
	
	}
}

當然我們可以自訂我們的init()函數

class someClass: NSObject {
	override init()	{
	
	}

	init(_ value: Int) {
		super.init()
	}
}

在類別中宣告的屬性或函數,區分為instance等級與class等級。兩者差別在instance等級要實體化後才可以使用它,而class等級則不用實體化即可使用。在屬性或是函數的宣告前面加入static,就代表它們是class等級。

class SomeClass: NSObject {
    let someStr = "這是一個instance 等級屬性"
    static let otherStr = "這是一個class 等級屬性"
    
    func someFuction() {
        print("這是一個instance 等級屬性")
    }

    static func otherFunction() {
        print("這是一個class 等級屬性")
    }
}
let testclass = SomeClass() //類別實體化
testclass.someStr
testclass.someFuction()


SomeClass.otherStr	//因為otherStr是class屬性,所以可以直接調用
SomeClass.otherFunction()

屬性(Property)

Swift中所有屬性都包含getter和setter函數,只是大部分我們都不需要覆寫它們,但某些情況我們要將值放到屬性中或是取出時需要先處理一下,這時候我們就要覆寫一下getter和setter函數了。


class newClass {
    var value: Int = 0
    
    var doubleValue: Int {
        get {
            return value
        }
        set(newValue) {
            value = newValue * 2
        }
    }
}

let testNewClass = newClass()
testNewClass.doubleValue = 10
print(testNewClass.doubleValue) //印出 20

並不是每次覆寫都要修改getter和setter,可以依需要指修改getter或setter,所以上例可以直接改寫getter就好

class newClass {
    var value: Int = 0
    
    var doubleValue: Int {
        get {
            return value * 2
        }
    }
}

let testNewClass = newClass()
testNewClass.value = 10	//注意這裡是設定value,而不是doubleValue
print(testNewClass.doubleValue) //印出 20

函數(Functions)

每個函數都有個函數名稱,用來描述函數執行的任務。當你定義一個函數時,你可以定義一個或多個有名字和資料型態的值,作為函數的輸入(內部參數)(parameters)。

要使用一個函數時,你用函數名「呼叫」,並傳給它匹配的輸入值(外部參數)(arguments)。一個函數的外部參數必須與函數的參數表裡參數的順序一致。

func whatTimeIsIt (time t: Int)  {
    
        print("Now is \(t) o'clock.")
}

whatTimeIsIt(time: 12) //印出"It is 12 o'clock."

上述例子中
函數名:whatTimeIsIt
外部參數名: time
內部參數名: t

Swift為了讓程式碼更方便閱讀,要求使用者在呼叫函數時,務必填寫外部參數名,否則會編譯錯誤,而函數內為求程式碼精簡,內部參數名通常會用簡稱或是縮寫。

  • 意外小插曲,parameter 和 argument之亂??
    parameter和argument到底差在哪??兩個都翻譯成參數??

Argument又翻譯成 「引數」,我稱之為『外部參數』,實際全名應為”actual argument” 才是那個實際的值

parameter又翻譯成「參數」,我稱之為『內部參數』,實際全名應為”formal parameter” 指的就是那個用來代表參數的符號而已

函數也可以定義任意資料型態的值作為函數執行結束的回傳值。只需要在函數宣告後方加上「->」符號與傳回值的資料型態,並在函數中使用return傳回即可。

func driverLicense (age a: Int) -> Bool {
    if a > 17 {
        return true
    } else {
        return false
    }
}
driverLicense(age: 19)  //印出true,因為大於17歲所以可以考取駕照

part II 就先到這告一個段落,明天還有最後一篇語法啊~~~
寫到眼睛都花了...


上一篇
Day 2 - swift 語法 (part I)
下一篇
Day 4 - swift 語法 (part III)
系列文
無中生有-從SWIFT語法學習到iOS APP的開發30

尚未有邦友留言

立即登入留言