<font color="#8A2BE2">[Udemy IOS Angela]</font> Ch9 iOS App Design Patterns and Code Structuring === # Ch9 Outline * Show quiz question * Check the answer * Lear Swift Structures * Model View Controller pattern * Function input/output * immutability ![](https://i.imgur.com/1aDUteg.png) ![](https://i.imgur.com/wgjTUaz.png) ## 96. Setting up the Quizzler Project and Showing the Questions! ## 97. Checking Answers using 2-Dimensional Arrays ![](https://i.imgur.com/oq1pcAg.png) ```swift! // // ViewController.swift // Quizzler-iOS13 // // Created by Angela Yu on 12/07/2019. // Copyright © 2019 The App Brewery. All rights reserved. // import UIKit class ViewController: UIViewController { @IBOutlet weak var questionLabel: UILabel! @IBOutlet weak var progressBar: UIProgressView! @IBOutlet weak var trueButton: UIButton! @IBOutlet weak var falseButton: UIButton! let quiz = [ ["第一題 4 加 2 等於 6", "True"], ["第二題 5 減 3 大於 1", "True"], ["第三題 3 加 8 比 10 小", "False"] ] var questionNumber = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. updateUI() //初始畫面就啟動函式 } @IBAction func answerButtonPressed(_ sender: UIButton) { let userAnswer = sender.currentTitle //True, False let actualAnswer = quiz[questionNumber][1] if userAnswer == actualAnswer { print("Right") } else { print("Wrong") } if questionNumber + 1 < quiz.count { questionNumber += 1 } else if questionNumber + 1 == quiz.count { questionNumber = 0 } updateUI() } //建立函式 func updateUI() { questionLabel.text = quiz[questionNumber][0] } } ``` # 98. [Swift Deep Dive] Structures, Methods and Properties ## 第一版 寫死 struct 屬性方法 ![](https://i.imgur.com/cT4TJ1C.png) ```swift! struct 城鎮 { //屬性 let 名字 = "台灣" var 市民 = ["蔡英文", "馬英九"] var 資源 = ["香蕉": 100, "鳳梨": 50, "西瓜" : 20] func 增強防衛() { print("來!加強防守") } } //方法 var 台灣城鎮 = 城鎮() print(台灣城鎮.市民) //["蔡英文", "馬英九"] print("\(台灣城鎮.名字) 有 \(台灣城鎮.資源["香蕉"]!) 幾包") //台灣 有 100 幾包 台灣城鎮.市民.append("陳水扁") print(台灣城鎮.市民.count) //3 台灣城鎮.增強防衛() //來!加強防守 ``` ## 不用self的話 init要多命名 ```swift! struct 城鎮 { let 名字: String var 市民: [String] var 資源: [String: Int] //不重複struct init(城鎮名稱: String, 人們: [String], 狀態: [String: Int]) { 名字 = 城鎮名稱 市民 = 人們 資源 = 狀態 } func 增強防衛() { print("來!加強防守") } } //套用init var 台灣城鎮 = 城鎮(城鎮名稱: "台灣", 人們: ["蔡英文"], 狀態: ["香蕉": 100]) print(台灣城鎮) //城鎮(名字: "台灣", 市民: ["蔡英文"], 資源: ["香蕉": 100]) //套用struct 台灣城鎮.市民.append("馬英九") print(台灣城鎮) //城鎮(名字: "台灣", 市民: ["蔡英文", "馬英九"], 資源: ["香蕉": 100]) ``` ![](https://i.imgur.com/BAGLoln.png) ## 完整 ```swift! struct 城鎮 { let 名字: String var 市民: [String] var 資源: [String: Int] // 發起一個承接城鎮的屬性 // 字串 陣列 字典 init(名字: String, 市民: [String], 資源: [String: Int]) { self.名字 = 名字 self.市民 = 市民 self.資源 = 資源 } func 增強防衛() { print("來!加強防守") } } var 台灣城鎮 = 城鎮(名字: "台灣", 市民: ["蔡英文"], 資源: ["香蕉": 100]) var 美國城鎮 = 城鎮(名字: "美國", 市民: ["拜登"], 資源: ["蘋果": 150]) 台灣城鎮.市民.append("馬英九") //城鎮(名字: "台灣", 市民: ["蔡英文", "馬英九"], 資源: ["香蕉": 100]) print(台灣城鎮) print("-------------") 美國城鎮.增強防衛() //來!加強防守 print(美國城鎮) //城鎮(名字: "美國", 市民: ["拜登"], 資源: ["蘋果": 150]) ``` ![](https://i.imgur.com/VMQnoT6.png) ## 編碼練習10 :::success [編碼練習] 結構 您即將創建下一個大型社交網絡應用程序,專供商業領袖使用,稱為 KingPin。 定義結構 作為此應用程序的一部分,您需要定義一個名為 User 的結構來表示用戶。 這個結構需要保留用戶名、電子郵件(可選)、關注者數量以及他們是否活躍。 User 結構需要具有以下屬性: 姓名 電子郵件? 追隨者 活躍 Struct 還需要有一個名為 logStatus() 的方法。 如果用戶處於活動狀態,則該方法需要打印“XXX 正在努力工作”。 否則,它需要打印“XXX 已離開地球”(其中 XXX 是用戶名)。 初始化結構 定義結構後,創建一個名為“Richard”的用戶,其中有 0 個不活躍的關注者。 然後使用 logStatus() 將此用戶的狀態打印到控制台。 要成功應對這一挑戰,控制台將需要讀取: ```swift! Richard has left earth Diagnostic code (i.e., Challenge Hint): Elon is working hard Contacting Elon on elon@tesla.com ... Elon has 2001 followers Elon has left earth ``` ::: ```swift! // Define the User struct here struct User { let name: String let email: String? let followers: Int var isActive: Bool init(name: String, email: String? = nil, followers: Int, isActive: Bool) { self.name = name self.email = email self.followers = followers self.isActive = isActive } func logStatus() { if isActive == true { print("\(name) is working hard") //self.name name print same answer } else { print("\(name) has left earth") } } } // Initialise a User struct here var richard = User(name: "Richard", email: "", followers: 0, isActive: false) richard.logStatus() ``` # 99. Creating a Question Struct ```swift! import Foundation struct Question { let text: String let answer: String init(q: String, a: String) { text = q answer = a } } ``` ![](https://i.imgur.com/3A7IRXa.png) ```swift= // // ViewController.swift // Quizzler-iOS13 // // Created by Angela Yu on 12/07/2019. // Copyright © 2019 The App Brewery. All rights reserved. // import UIKit class ViewController: UIViewController { @IBOutlet weak var questionLabel: UILabel! @IBOutlet weak var progressBar: UIProgressView! @IBOutlet weak var trueButton: UIButton! @IBOutlet weak var falseButton: UIButton! //題目變數 let quiz = [ Question(q: "第一題 4 加 2 等於 6", a: "True"), Question(q: "第二題 5 減 3 大於 1", a: "True"), Question(q: "第三題 3 加 8 比 10 小", a: "False"), ] var questionNumber = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. updateUI() //初始畫面就啟動函式 } @IBAction func answerButtonPressed(_ sender: UIButton) { let userAnswer = sender.currentTitle //True, False let actualQuestion = quiz[questionNumber] //[ , , ,] let actualAnswer = actualQuestion.answer if userAnswer == actualAnswer { print("Right") } else { print("Wrong") } if questionNumber + 1 < quiz.count { questionNumber += 1 } else if questionNumber + 1 == quiz.count { questionNumber = 0 } updateUI() } //建立函式 更換題目 //因為這函式吃不到 IBAction func answerButtonPressed 內的東西,要吃最外面let quiz func updateUI() { questionLabel.text = quiz[questionNumber].text } } ``` ![](https://i.imgur.com/FQZpn5c.png) # 100. Giving the User Feedback and working with a ProgressView ```swift! import UIKit class ViewController: UIViewController { @IBOutlet weak var questionLabel: UILabel! @IBOutlet weak var progressBar: UIProgressView! @IBOutlet weak var trueButton: UIButton! @IBOutlet weak var falseButton: UIButton! //題目變數 let quiz = [ Question(q: "A slug's blood is green.", a: "True"), Question(q: "Approximately one quarter of human bones are in the feet.", a: "True"), Question(q: "The total surface area of two human lungs is approximately 70 square metres.", a: "True"), Question(q: "In West Virginia, USA, if you accidentally hit an animal with your car, you are free to take it home to eat.", a: "True"), Question(q: "In London, UK, if you happen to die in the House of Parliament, you are technically entitled to a state funeral, because the building is considered too sacred a place.", a: "False"), Question(q: "It is illegal to pee in the Ocean in Portugal.", a: "True"), Question(q: "You can lead a cow down stairs but not up stairs.", a: "False"), Question(q: "Google was originally called 'Backrub'.", a: "True"), Question(q: "Buzz Aldrin's mother's maiden name was 'Moon'.", a: "True"), Question(q: "The loudest sound produced by any animal is 188 decibels. That animal is the African Elephant.", a: "False"), Question(q: "No piece of square dry paper can be folded in half more than 7 times.", a: "False"), Question(q: "Chocolate affects a dog's heart and nervous system; a few ounces are enough to kill a small dog.", a: "True") ] var questionNumber = 0 //預設一進入畫面 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. updateUI() //初始畫面就啟動函式 } //點擊True或False按鈕 @IBAction func answerButtonPressed(_ sender: UIButton) { let userAnswer = sender.currentTitle //True, False let actualQuestion = quiz[questionNumber] //[ , , ,] let actualAnswer = actualQuestion.answer if userAnswer == actualAnswer { sender.backgroundColor = UIColor.green } else { sender.backgroundColor = UIColor.red } if questionNumber + 1 < quiz.count { questionNumber += 1 } else if questionNumber + 1 == quiz.count { questionNumber = 0 } Timer.scheduledTimer(timeInterval: 0.2, target:self, selector: #selector(updateUI), userInfo:nil, repeats: false) } //建立函式 更換題目 //因為這函式吃不到 IBAction func answerButtonPressed 內的東西,要吃最外面let quiz @objc func updateUI() { //改成object c 函式 questionLabel.text = quiz[questionNumber].text trueButton.backgroundColor = UIColor.clear falseButton.backgroundColor = UIColor.clear progressBar.progress = Float(questionNumber + 1) / Float(quiz.count) } } ``` ![](https://i.imgur.com/wdXC6ct.png) # 101. Understand the MVC Design Pattern ![](https://i.imgur.com/1ofbkkb.png) MVC # 102. Implementing MVC and Understanding Parameter Names # 103. ![](https://i.imgur.com/yfjCCIz.png) ![](https://i.imgur.com/O9EXNWA.png) ![](https://i.imgur.com/RmvglBY.png) ![](https://i.imgur.com/c8KqEuW.png) ## 編碼練習11 :::success [編碼練習] 函數第 3 部分 使用您所了解的關於可以有輸出的函數的知識,創建一個名為 isOdd(n: Int) 的函數。 對於傳遞給函數的任何給定整數,例如 奇數(n:5) 該函數將測試數字是否為奇數。 如果是,那麼它應該輸出 true,否則它應該輸出 false。 這些是布爾值而不是字符串。 注意:您不應編寫任何打印語句。 只有當結果是輸出時,測試才會通過。 提示:您可以使用餘數運算符來檢查是否可以乾淨地劃分某些內容。 https://docs.swift.org/swift-book/LanguageGuide/BasicOperators.html#ID64 在不更改任何現有代碼的情況下,您的函數應該能夠輸出結果。 在這個 Repl.it 中嘗試一些代碼:https://repl.it/@appbrewery/functions-3-exercise#main.swift ::: ```swift! //Create your function here 👇 func isOdd(n: Int) -> Bool { if n % 2 == 0 { return false } else { return true } } isOdd(n: 5) //true ``` # 105. [Swift Deep Dive] Immutability ```swift! struct 城鎮 { let 名字: String var 市民: [String] var 資源: [String: Int] // 發起一個承接城鎮的屬性 // 字串 陣列 字典 init(名字: String, 市民: [String], 資源: [String: Int]) { self.名字 = 名字 self.市民 = 市民 self.資源 = 資源 } func 增強防衛() { print("來!加強防守") } mutating func 收割米() { 資源["米"] = 200 //其實是 self.資源["米"] = 100 因為self不能改 但是mutating讓self變成var } } var 台灣城鎮 = 城鎮(名字: "台灣", 市民: ["蔡英文"], 資源: ["香蕉": 100]) 台灣城鎮.市民.append("馬英九") //城鎮(名字: "台灣", 市民: ["蔡英文", "馬英九"], 資源: ["香蕉": 100]) print(台灣城鎮) 台灣城鎮.收割米() //強制改變了struct結構 print(台灣城鎮) //城鎮(名字: "台灣", 市民: ["蔡英文", "馬英九"], 資源: ["香蕉": 100, "米": 200]) ``` # 106. ###### tags: `[Udemy IOS Angela Yu]`