iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 5
0
Software Development

給我 30 天,給你一輩子:Swift 從零開始系列 第 5

Day 5 | Swift 基本番外篇之 Assertions

  • 分享至 

  • xImage
  •  

Assertions and Preconditions

什麼時候該用 assertions、preconditions 還有 fatalError 呢?


這是延續 Swift 基礎篇 的小小番外篇,今晚,我想來點 Assertions and Preconditions

針對程式碼,我們很常使用到判斷式來決定要做什麼事情,有的時候也會期待一個變數或常數經過透過某個 Function 或是處理之後,應該要符合某種特定條件。

Swift 提供了這兩種方法,讓開發者表達所設的假設與期望,確保透過這兩個條件驗證結果符合你所預期的結果。


Assertions

Assertion 就中文意思來說就是斷言或是明確肯定,顧名思義可以用來保證某個條件是否為真。

剛剛提到他可以用來判斷邏輯,所以條件判斷結果為真的時候,程式碼就會看起來像沒事一樣地繼續往下執行,但如果判斷結果為否,程式碼就會立即中斷,對於 APP End-User 的角度來看,就是俗稱的 Crash

國文的分數必須是 0 分以上,不可以有負數的情況,所以透過 Global Function assert(國文分數 > 0) 來進行判斷,如果條件通過程式碼才能繼續執行,我們來看底下的範例:

var 國文分數 = 87
assert(國文分數 > 0)

但是,不通過會怎麼樣嗎?

var 國文分數 = -1
assert(國文分數 > 0)
// Assertion failed: file ..., line 2

Assertion error

在 Xcode 中就會跳出錯誤訊息,並且跟你說程序已被中斷,並且在 Output 印出 Assertion failed,還提醒你錯在第幾行,貼心 <3。

但是這樣的錯誤訊息,現在練習當然很清楚知道錯在哪裡,但是如果是在好幾萬行 Code 的專案中,還是希望可以不用透過觀落陰考古,才能得知為什麼錯,我們來看一下官方 API Swit > Assert有什麼提示可以新增:

public func assert(_ condition: @autoclosure () -> Bool,
                    _ message: @autoclosure () -> String = String(),
					file: StaticString = #file, line: UInt = #line)

可以從上面發現,原來有個 message 可以使用,官方 API 對於 message 是這樣說明:A string to print if condition is evaluated to false. The default is an empty string.message 這個 Parameter 預設值是空字串,所以我們更清楚地知道,原來是可以加註一些說明,這樣一來在發生判斷失敗的時候,就可以快速知道是什麼錯誤原因。

var 國文分數 = -1
assert(國文分數 > 0, "分數不可以為負數!")
// Assertion failed: 分數不可以為負數!: file ...

還有一個 assertionFailure(),這個方法你可以把它想像成 assert(false),會讓程式碼中斷,例如你可以用別人的Code中在 Switch Control Flow 的 Default 中加上 assertionFailure(),條件都不符合的時候執行中斷。

Preconditions

先來看個案例,針對字串轉整數的初始化方法(之後會介紹),可以到 Swift GitHub ( swift/stdlib/public/core/IntegerParsing.swift ) 上看到這個初始化方法的原始碼,在 152 行可以發現,也有用到 precondition來去做 radix 的判斷。

preconditions 其實跟 assertions 很像,連 API 都長得 87% 像,都是用來判斷條件。

public func precondition(_ condition: @autoclosure () -> Bool,
                    _ message: @autoclosure () -> String = String(),
					file: StaticString = #file, line: UInt = #line)

當然 Precondition 也有 preconditionFailure()

但是這樣跟 assertions 到底有什麼差別呢?差別就在於 assertions 只會在 Debug 環境下被編譯執行,在 Release 則不會,可以簡單開個 Xcode Project

  • 點選 *.xcodeproject檔案 > Build Setting > Apple Clang - Code Generation > Optimization Level

我們可以看到 Debug 的 Optimization LevelNone[-O0];Release 的則是 Fastest, Smallest [-Os],在預設的情況下,Debug 環境對於優化的等級採最低限度地優化,也意味著會完全保留所有 debug 資訊,如果想知道更多 Optimization Level 的消息,可以到 GCC 官網的文件查看。

除了 assertions 在優化等級的限制,preconditions 也有特別的規則,在 [-Ounchcked] 的規則下,preconditions 不會被檢查。

但有一個特別的方法不受到優化等級的限制,叫做 FatalError(),跟 assertionFailure 還有 preconditionFailure 很類似,一樣都會無條件中斷程序。

中文意思又叫做致命錯誤,聽起來有點中二,但確實是蠻危險的。

無論在什麼等級下都不會被優化,所以在任何環境都會執行,所以在使用的時候盡量避免,除非很明確的知道判斷結果為否的嚴重性跟 FatalError 是差不多的,再去使用,官方 API 是建議可以這麼做:

在還沒開發完成的地方加上 fatalError("Unimplemented"),在編譯的時候,跳出錯誤訊息,告訴開發人員還有地方沒有完成。


上一篇
Day 4 | Swift 字串和字元
下一篇
Day 6 | Swift 特別型別:Optionals
系列文
給我 30 天,給你一輩子:Swift 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言