<font color="#8A2BE2">[Udemy IOS Angela]</font> Ch8 Control Flow and Optionals
===
# Ch8 Outline
* Project Skeleton
* If/Else Statement
* Switch Statement
* Dictionay
* Optionals
* UIProgressView track of time
* Debug App
## 81. Setting up the Egg Timer Project and Linking the Storyboard and ViewController


寫法

Angela解法


```swift=
print(sender.currentTitle) //Optionals + 文字
print(sender.currentTitle!) //抓點擊的文字
print(sender.titleLabel!.text!) //抓文字
```
### 點擊蛋,分別印出不同時間

## 82. IF/ELSE
```swift=
if trafficLight == "green" {
go()
} else if trafficLight == "amber" {
useYourJudegement()
} else {
stop()
}
```
### 相愛一輩子vs孤單一輩子
```swift=
//建立函式loveCalculator
//隨機生成數字
//存成一個loverScore變數
//如果變數是100 印出 相親相愛
//不然就印出 孤單一輩子
func loveCalculator(){
let loverScore = Int.random(in: 0...100)
if(loverScore == 100) {
print("\(loverScore)相愛一輩子")
} else {
print("\(loverScore)孤單一輩子")
}
}
loveCalculator()
loveCalculator()
loveCalculator()
loveCalculator()
```

```swift=
* == 等於
* != 不等於
* > 大於
* < 小於
* >= 大於等於
* <= 小於等於
&& AND
|| OR
! NOT
```
### 相愛一輩子vs相愛一下子vs孤單一輩子
```swift=
//建立函式loveCalculator
//隨機生成數字
//存成一個loverScore變數
//如果變數是100 印出 相親相愛
//不然就印出 孤單一輩子
func loveCalculator(){
let loverScore = Int.random(in: 0...100)
if(loverScore >= 80) {
print("\(loverScore)相愛一輩子")
} else if(loverScore >= 40 && loverScore <= 80) {
print("\(loverScore)相愛一下子")
}else {
print("\(loverScore)孤單一輩子")
}
}
loveCalculator()
loveCalculator()
loveCalculator()
loveCalculator()
```

### 編碼練習 6: [Coding Exercise] IF/ELSE 閏年/平年
```swift=
/*
每四年一個閏年,該年會多1天,366天
閏年3個條件
條件1. 年份可以被四整除(沒有提示)則為閏年,除非:
條件2. 如果年份也可以被 100 整除(以兩個零結尾的年份),那麼它不是閏年,除非
條件3. 它也可以被 400 整除(在這種情況下它將是閏年)。
1997 年不是閏年,
1996 年是
1900 年不是閏年 被4整除,年份被100整除,所以不是
2000 年是。 被4整除,年份被100整除,滿足年份被被400整除
*/
//Don't change this
var aYear = Int(readLine()!)! //互動,等待使用者輸入年份
func isLeap(year: Int) {
//Write your code inside this function.
//isLeap(year: aYear)
//year is the parenthesise name
//aYear is the value
if( (year % 4 ) != 0 ) {
print("No")
}
if( year % 4 == 0 && year % 100 == 0 && year % 400 == 0) { //1200will be in this line print YES
print("YES")
} else if( year % 4 == 0 && year % 100 == 0 ) {
print("NO")
} else if( year % 4 == 0 ) {
print("YES")
}
}
//Try out your function with some different years. Don't copy the line below (it's not part of the exercise you need to complete).
isLeap(year: aYear)
```

## 83. [Swift Deep Dive] Switch Statements
```swift=
當案例很多Switch 就很好用
switch hardness {
case "Soft":
print(5)
case "Medium"
print(7)
case "Hard":
print(12)
default:
print("Error")
}
```
```swift=
a...b 介於a到b之間
a..<b 介於a到b-1之間
...b 任何小於b的數字
```
:::info
switch判斷語法 + switch改成布林判斷
```swift=
func loveCalculator() {
let loverScore = Int.random(in: 0...100)
switch true {
case loverScore>=80:
print("\(loverScore)相愛一輩子")
case (loverScore>=40&&loverScore<=80):
print("\(loverScore)相愛一下子")
case (loverScore<=40):
print("\(loverScore)孤單一輩子")
default:
print("輸入不存在我的判斷")
}
}
loveCalculator()
loveCalculator()
loveCalculator()
loveCalculator()
```

圖片需修正,依據程式碼為主(81...100 41...80)
:::
:::danger
switch判斷語法 + a...b介於數字寫法
```swift=
func loveCalculator() {
let loverScore = Int.random(in: 0...100)
switch loverScore {
case 81...100:
print("\(loverScore)相愛一輩子")
case 41..<80:
print("\(loverScore)相愛一下子")
case ...40:
print("\(loverScore)孤單一輩子")
default:
print("輸入不存在我的判斷")
}
}
loveCalculator()
loveCalculator()
loveCalculator()
loveCalculator()
```

圖片需修正,依據程式碼為主(81...100 41...80)
:::
### 編碼練習 7: [Coding Exercise] Switch
```swift=
[編碼練習] 開關
創建一個程序,將數字 (Int) 作為輸入並使用 Switch 語句打印相應的星期幾。
例如如果輸入是 5
然後函數應該打印:
“星期五”
如果輸入的數字與星期幾不匹配,那麼您的程序應該打印“錯誤”。
您可以在此處試用您的代碼:https://repl.it/@appbrewery/switch-exercise#main.swift
提示:打印的工作日需要首字母大寫且拼寫正確才能通過測試。
```
```swift=
////Don't change this
var aNumber = Int(readLine()!)!
func dayOfTheWeek(day: Int) {
//Write your code inside this function.
switch day {
case 1 : print("Monday")
case 2 : print("Tuesday")
case 3 : print("Wednesday")
case 4 : print("Thursday")
case 5 : print("Friday")
case 6 : print("Saturday")
case 7 : print("Sunday")
default: print("Error")
}
}
dayOfTheWeek(day: aNumber)
```



[參考](https://www.udemy.com/course/ios-13-app-development-bootcamp/learn/quiz/5037444#questions/13786852)
## 84. Conditional Statements Challenge Solution
```swift=
import UIKit
class ViewController: UIViewController {
let softTime = 5
let mediumTime = 7
let hardTime = 12
//挑戰1
//建立一個按鈕hardnessSelected IBAction
//連接到3個蛋
//按下蛋會印出Soft Medium Hard字樣
@IBAction func hardnessSelected(_ sender: UIButton) {
//print(sender.currentTitle!) //抓點擊的文字
let hardness = sender.currentTitle //把點擊文字變成一個變數
//挑戰2
//點擊Soft 印出5 ; Medium 印出7 ; Hard 印出12
if(hardness == "Soft"){
print("\(softTime)")
}else if(hardness == "Medium"){
print("\(mediumTime)")
}else if(hardness == "Hard"){
print("\(hardTime)")
}
}
}
```

## 85. [Swift Deep Dive] Dictionaries
```swift=
key value
var dict = ["Brewery" : "a place where beer is made",
"Bakery" : "a place where bread is made"]
key字串 value整數
var dict : [String : Int] = ["Angela" :7712345678,
"Philipp" : 7787654321]
dict["Angela"] //印出7712345678
```
### 編碼練習 8: [Coding Exercise] Dictionaries
```swift=
[編碼練習] 字典
添加新條目
Slack Technologies Inc 是 Slack 背後的公司,
Slack 是流行的消息傳遞和協作工具,最近於 2019 年 4 月首次公開募股。
它在紐約證券交易所上市,股票代碼為 WORK。
使用鍵“WORK”和值“Slack Technologies Inc”
向 stockTickers 字典添加一個條目。
更新現有值
Dynamic Materials Corp 是一家專門從事爆炸金屬加工
(如熔覆或衝擊硬化)的公司。但是,
公司的正式名稱不是“Dynamic Materials”,
而是“DMC Global Inc”。將股票代碼 BOOM 的值更新為“DMC Global Inc”。
```
```swift=
func exercise() {
//Don't change this
var stockTickers: [String: String] = [
"APPL" : "Apple Inc",
"HOG": "Harley-Davidson Inc",
"BOOM": "Dynamic Materials",
"HEINY": "Heineken",
"BEN": "Franklin Resources Inc"
]
//Write your code here.
stockTickers["WORK"] = "Slack Technologies Inc" //添加字典內容
stockTickers["BOOM"] = "DMC Global Inc" //修改既有字典內容
//Don't modify this
print(stockTickers["WORK"]!)
print(stockTickers["BOOM"]!)
}
exercise()
```
[參考](https://www.tutorialkart.com/swift-tutorial/swift-dictionary-append-element/)
## 86. [Swift Deep Dive] Defining and Unwrapping Optionals
:::danger
optional就像是箱子內貓與毒藥放在一起,你不知道裡面貓是活的還是死的
nil 裡面的貓死了
:::
```swift=
var hardness :String? //變數hardness 資料類別是字串,目前值可以是『有東西』或是『空值』都行
var player1Username: String = nil //建立變數報錯
var player1Username: String? = nil //建立變數可以執行
player1Username = "AngelaIsAwesome" //變數賦值
print(player1Username) //印出 Optional("AngelaIsAwesome")
print(player1Username!) //印出 AngelaIsAwesome
//!就像是安全檢查,防止我們在嘗試用空值去做事情讓程式崩潰
var unwrappedP1Username = player1Username! //建立新變數,把Optional("AngelaIsAwesome") 賦值給新變數
player1Username = nil //把原本值刪除,設定為空
print(player1Username) //player1Username是空nil
print(player1Username!) //報錯,會通知,這樣印有可能會印出空
//建議用if來保護
if player1Username != nil { //如果不是空,會印東西,是空,就不會印
print(player1Username!)
}
```
### 編碼練習 9: [Coding Exercise] Optionals
```swift=
[編碼練習] 可選
如果你有一本字典,裡面有 3 個學生的名字和他們的考試成績,你能打印出最高分嗎?
例如如果
studentsAndscores = [“艾米”:88,“詹姆斯”:55,“海倫”:99]
然後你的函數應該打印 99。
但是你不知道分數是多少,所以你的程序必須處理所有的可能性!
提示:當你使用鍵從字典中取出值時,出來的值是可選的!
請務必使用示例輸入測試您的代碼,並在此處試用您的代碼:https://repl.it/@appbrewery/optionals-exercise#main.swift
```
```swift=
//Don't change this
var studentsAndScores = ["Amy": Int(readLine()!)!, "James": Int(readLine()!)!, "Helen": Int(readLine()!)!]
func highestScore(scores: [String: Int]) { //建立一個函式
//Write your code here.
//print(scores) //會印出全部參數的值
//print(studentsAndScores.values.max()) //Optional(92)
print(studentsAndScores.values.max()!)
}
//Try some different scores.
//Dont add the lines below to udemy!
highestScore( //呼叫函式
scores: ["Amy": 78, "James": 65, "Helen": 92]
)
```


[參考字典找最大值](https://stackoverflow.com/questions/72731141/print-the-key-of-the-max-value-from-a-dictionary-swift)
## 87. Dictionary Challenge Solution
print 加上驚嘆號


## 88. Implementing a Countdown Timer Challenge
建立一個時間倒數器
```swift=
class ViewController: UIViewController {
var secondsRemaining = 30
@IBAction func startTimer(_ sender: UIButton) {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (Timer) in
if self.secondsRemaining > 0 {
print ("\(self.secondsRemaining) seconds")
self.secondsRemaining -= 1
} else {
Timer.invalidate()
}
}
}
```

[參考](https://stackoverflow.com/questions/29374553/how-can-i-make-a-countdown-with-nstimer)
Angela版本
```swift=
import UIKit
class ViewController: UIViewController {
//使用字典資料結構
let eggTimes = ["Soft": 300, "Medium": 420, "Hard": 720]
var secondsRemaining = 60
@IBAction func hardnessSelected(_ sender: UIButton) {
let hardness = sender.currentTitle! //把點擊文字變成一個變數
secondsRemaining = eggTimes[hardness]! //倒數秒數依據點擊蛋秒數不同
//倒數libary 間隔1秒
Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
}
//Object C libary
@objc func updateTimer() {
if secondsRemaining > 0 {
print ("\(secondsRemaining) seconds")
secondsRemaining -= 1
}
}
}
```
:::danger
這程式有個問題,當點擊Soft圖,又再點擊Medium圖,又再點擊Hard圖
一秒會跑3個second
原因
17行Timer.scheduledTimer()並未真正取消,每點擊一個蛋會執行17行,而且又會呼叫21行@objc func updateTimer()
當一直點擊每秒倒數數度會越增越多,速度越來越快
:::

## 89. Egg Timer Challenge Solution
```swift=
import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft": 300, "Medium": 420, "Hard": 720]
var secondsRemaining = 60
var timer = Timer() //建立一個時間變數
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate() //每次點擊之前的變數變成無效
let hardness = sender.currentTitle! //把點擊文字變成一個變數
secondsRemaining = eggTimes[hardness]!
//把計時libary設為一個變數
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
}
@objc func updateTimer() {
if secondsRemaining > 0 {
print ("\(secondsRemaining) seconds")
secondsRemaining -= 1
}
}
}
```
### 秒數倒數完,畫面文字改變
修改處
```swift=
@IBOutlet weak var eggText: UILabel!
@objc func updateTimer() {
if(secondsRemaining == 0) {
self.eggText.text = "Done"
}
}
```
參考StackOverflow
```swift=
import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft": 3, "Medium": 4, "Hard": 7]
var secondsRemaining = 60
var timer = Timer()
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle! //把點擊文字變成一個變數
secondsRemaining = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
}
把文字拉成程式
@IBOutlet weak var eggText: UILabel!
@objc func updateTimer() {
if secondsRemaining > 0 {
print ("\(secondsRemaining) seconds")
secondsRemaining -= 1
當0秒時
if(secondsRemaining == 0) {
self.eggText.text = "Done"
}
}
}
}
```


[參考](https://stackoverflow.com/questions/24275632/how-do-i-change-text-in-a-label-with-swift)
Angela
```swift=
//標籤拉成程式碼
@IBOutlet weak var eggText: UILabel!
else {
timer.invalidate() //時間暫停
eggText.text = "Done" //文字顯示完成
}
```
```swift=
import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft": 3, "Medium": 4, "Hard": 7]
var secondsRemaining = 60
var timer = Timer()
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle! //把點擊文字變成一個變數
secondsRemaining = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
}
//標籤拉成程式碼
@IBOutlet weak var eggText: UILabel!
@objc func updateTimer() {
if secondsRemaining > 0 {
print ("\(secondsRemaining) seconds")
secondsRemaining -= 1
} else {
timer.invalidate() //時間暫停,不再計時
eggText.text = "Done" //文字顯示完成
}
}
}
```
## 90. Showing the Timer to the User with a Progress View




0.5代表剩下1/2

0.1代表勝下1/10

### 點擊一次,進度條直接變成100%
新加入
```swift=
@IBOutlet weak var progressView: UIProgressView!
progressView.progress = 1
```
全部code
```swift=
import UIKit
class ViewController: UIViewController {
let eggTimes = ["Soft": 3, "Medium": 4, "Hard": 7]
var secondsRemaining = 60
var timer = Timer()
@IBOutlet weak var progressbar: UIView!
@IBOutlet weak var progressView: UIProgressView!
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle! //把點擊文字變成一個變數
secondsRemaining = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
print(progressbar!)
progressView.progress = 1
}
//標籤拉成程式碼
@IBOutlet weak var eggText: UILabel!
@objc func updateTimer() {
if secondsRemaining > 0 {
print ("\(secondsRemaining) seconds")
secondsRemaining -= 1
} else {
timer.invalidate() //時間暫停
eggText.text = "Done" //文字顯示完成
}
//else if{progressBar.progress == Float }
}
}
```

[參考](https://stackoverflow.com/questions/31432777/swift-creating-a-progress-bar)
Angela
```swift=
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var titleLabel: UILabel!
let eggTimes = ["Soft": 3, "Medium": 4, "Hard": 7]
var secondsRemaining = 60
var timer = Timer()
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle!
secondsRemaining = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
progressBar.progress = 1
}
@objc func updateTimer() {
if secondsRemaining > 0 {
print ("\(secondsRemaining) seconds")
secondsRemaining -= 1
} else {
timer.invalidate() //時間暫停
titleLabel.text = "Done" //文字顯示完成
}
}
}
```

## 91. Calculating the Progress Percentage
讓進度條顯示剩餘的時間
progress 0 -> 1 (秒數/100逐次加總)
secondsRemaining = progress.text
* 顯示百分比 56% = 0.56
* 不同蛋不同秒數 soft egg 300秒/hard egg 720秒 走過秒數/總時間=進度百分比
* updateTime函式每秒做一個動作
執行,點擊蛋,進度條直接下降0卻沒有動作
```swift=
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var titleLabel: UILabel!
let eggTimes = ["Soft": 3, "Medium": 4, "Hard": 7]
//var secondsRemaining = 60
var timer = Timer()
var totalTime = 0 //總時間
var secondPassed = 0 //起始時間
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle!
totalTime = eggTimes[hardness]!
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
//progressBar.progress = 1.0
}
@objc func updateTimer() {
if secondPassed < totalTime {
let percentageProgress = secondPassed / totalTime //走過秒數/總時間=進度百分比
progressBar.progress = Float(percentageProgress) //progress是浮點數0.1這種數字
secondPassed += 1
} else {
timer.invalidate() //時間暫停
titleLabel.text = "Done" //文字顯示完成
}
}
}
```

## 92. Using the 5 Step Approach to Debug our App
```swift=
各自變成浮點數,再除才會得到2.5這樣小數,不然都會是2.0
let a = 5
let b = 2
print(a / b) //2
print(Float(a / b)) //2.0
print(Float(a) / Float(b)) //2.5
```
```swift=
import UIKit
import AVFoundation //匯入音檔
class ViewController: UIViewController {
var player: AVAudioPlayer! //建立音檔變數
@IBOutlet weak var progressBar: UIProgressView!
@IBOutlet weak var titleLabel: UILabel!
let eggTimes = ["Soft": 3, "Medium": 4, "Hard": 7]
//var secondsRemaining = 60
var timer = Timer()
var totalTime = 0
var secondPassed = 0
@IBAction func hardnessSelected(_ sender: UIButton) {
timer.invalidate()
let hardness = sender.currentTitle! //變數hardness就是我們點擊的東西名稱
totalTime = eggTimes[hardness]!
progressBar.progress = 0.0
secondPassed = 0
titleLabel.text = hardness
timer = Timer.scheduledTimer(timeInterval: 1.0, target:self, selector: #selector(updateTimer), userInfo:nil, repeats: true)
playSound()
}
//音樂函式(參考之前音樂範例檔案)
func playSound() {
let url = Bundle.main.url(forResource: "alarm_sound", withExtension: "mp3")
player = try! AVAudioPlayer(contentsOf: url!)
player.play()
}
@objc func updateTimer() {
if secondPassed < totalTime {
secondPassed += 1 //先加再計算百分比
progressBar.progress = Float(secondPassed) / Float(totalTime)
print(Float(secondPassed) / Float(totalTime))
} else {
timer.invalidate() //時間暫停
titleLabel.text = "Done" //文字顯示完成
}
}
}
```

###### tags: `[Udemy IOS Angela Yu]`