和 if let 很像的 guard let

guard 什麼都學 if,所以自然的,它也有個跟 optional binding 的 if let 很像的 guard let,專門判斷 optional 是否有值和讀取它的內容。

ps: 還不認識 guard 的朋友,可先參考以下連結的說明:

guard let 的基本語法

  • 寫法 1
func showName(name: String?) {
guard let name else { return }
print("my name is \(name)")
}
  • 寫法 2
func showName(name: String?) {
guard let name = name else { return }
print("my name is \(name)")
}

輸入 guard let 時,我們也可從 Xcode 的選單選擇 guardlet,讓它幫我們自動填入 guard let else 的基本格式。

值得注意的,如果 else { } 裡只要單純地 return,沒有要做其它事情,我們習慣將它寫在同一行,讓程式看起來更精簡。

guard let name else { return }

guard let 和 if let 的作用大同小異,同樣可讓 let 後的常數名和 optional 同名,主要的差別在以下幾個地方:

  • guard let 的 else { } 程式將在 optional 無值時執行,跟 if let 相反,if let 的 { } 程式將在 optional 有值時執行。
  • guard let 後的常數可在 guard let else { } 後繼續使用,if let 後的常數只能在 if let 的 { } 裡使用。

name 可在 guard let { } 後繼續使用,因此 \( ) 裡的 name 型別是 String。

func showName(name: String?) {
guard let name else { return }
print("my name is \(name)")
}

以下程式 \( ) 裡的 name 是 showName 的參數 name,不是 if let 後的 name,因此它的型別是 String?。

func showName(name: String?) {
if let name {

}
print("my name is \(name)")
}
  • guard let { } 的程式必須離開原本 guard let 所在區塊,實現提早離開(early exit)的效果,因此 else 裡必須加入 return,break,continue 或 throw。

guard let 搭配 App 的表單輸入頁面

App 的表單輸入頁面很適合搭配 guard let 檢查欄位。比方我們做了一個通訊錄 App, 在新增聯絡人時,程式須做許多檢查,假設新增聯絡人的欄位有十個,我們可用十個 guard let 檢查是否每個欄位都有值,一旦某個 guard let 出錯即顯示錯誤,不再往下執行。唯有通過十個 guard let 的層層考驗,才會執行最後新增聯絡人的動作。

跟 if let 一樣,guard let 也可以串接多個 optional,因此檢查表單欄位新增資料的例子,將可寫成以下的 createBook function。

func createBook(title: String?, price: Double?, pages: Int?) {
guard let title,
let price,
let pages else { return }
// 以下區塊可加入新增 Book 的程式碼
print("\(title) costs $\(price) and has \(pages) pages.")
}

createBook(title: "彼得潘的 Swift 程式設計入門", price: 99999, pages: 1000)

比起原本 if let 的寫法,guard let 看起來可讀性更佳,因為它少了一層縮排,而且更清楚表達建立資料的相關程式在 else { } 之後。

func createBook(title: String?, price: Double?, pages: Int?) {
if let title,
let price,
let pages {
// 以下區塊可加入新增 Book 的程式碼
print("\(title) costs $\(price) and has \(pages) pages.")
}
}

跟 if let 一樣,當我們利用 guard let 讀出 optional 的內容後,還可以針對內容做判斷,例如以下例子判斷金額超過 1000 的書才是好書。

func createBook(title: String?, price: Double?, pages: Int?) {
guard let title,
let price,
let pages,
price > 1000 else { return }
// 以下區塊可加入新增 Book 的程式碼
print("\(title) costs $\(price) and has \(pages) pages.")
print("It is a good book!")
}

createBook(title: "彼得潘的 Swift 程式設計入門", price: 99999, pages: 1000)

開發 iOS App 時使用 guard let 的例子

利用 guard let 得到 cell

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "LoverTableViewCell", for: indexPath) as? LoverTableViewCell else { return UITableViewCell() }
let lover = lovers[indexPath.row]
cell.nameLabel.text = lover.name
cell.photoImageView.image = UIImage(named: lover.imageName)
return cell
}

在 prepare 裡利用 guard let 檢查是否可以傳資料

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let loverDetailViewController = segue.destination as? LoverDetailViewController,
let row = tableView.indexPathForSelectedRow?.row else { return }
loverDetailViewController.lover = lovers[row]
}

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com