Swift 语法学习之如何用代码调试程序?
断言和先决条件
断言和先决条件都是用来检测程序是否是在一个正确的状态中运行,它作用于程序发生时。它们能够帮助你在开发过程中找到错误和不正确的假定。
断言
使用全局函数 assert()
来说书写一个断言,官方源码如下:
/// Performs a traditional C-style assert with an optional message.
///
/// Use this function for internal sanity checks that are active during testing
/// but do not impact performance of shipping code. To check for invalid usage
/// in Release builds, see `precondition(_:_:file:line:)`.
///
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug
/// configuration): If `condition` evaluates to `false`, stop program
/// execution in a debuggable state after printing `message`.
///
/// * In `-O` builds (the default for Xcode's Release configuration),
/// `condition` is not evaluated, and there are no effects.
///
/// * In `-Ounchecked` builds, `condition` is not evaluated, but the optimizer
/// may assume that it *always* evaluates to `true`. Failure to satisfy that
/// assumption is a serious programming error.
///
/// - Parameters:
/// - condition: The condition to test. `condition` is only evaluated in
/// playgrounds and `-Onone` builds.
/// - message: A string to print if `condition` is evaluated to `false`. The
/// default is an empty string.
/// - file: The file name to print with `message` if the assertion fails. The
/// default is the file where `assert(_:_:file:line:)` is called.
/// - line: The line number to print along with `message` if the assertion
/// fails. The default is the line number where `assert(_:_:file:line:)`
/// is called.
public func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line)
从注释可以看出 assert()
函数接受四个参数 :
-
condition
:传入一个值为true
或false
的表达式; -
message
:写入一条在上面表达式结果为false
时会打印出来的提示信息 -
file
: 日志文件名 -
line
: 打印的行数
这后两个参数并非都需要传入,因为后两者都有默认值!下面是一些实例:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// this causes the assertion to trigger because age is not >= 0
如果你不想打印任何断言信息,也可以像这样使用:
assert(age >= 0)
如果代码已经检查了条件,你可以使用 assertionFailure(_:file:line:)
函数来标明断言失败,比如:
if age > 10 {
print("You can ride the roller-coaster or the Ferris wheel.")
} else if age > 0 {
print("You can ride the Ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
`assertionFailure(_:file:line:) 函数的官方定义如下:
/// Indicates that an internal sanity check failed.
///
/// Use this function to stop the program, without impacting the performance of
/// shipping code, when control flow is not expected to reach the call---for
/// example, in the `default` case of a `switch` where you have knowledge that
/// one of the other cases must be satisfied. To protect code from invalid
/// usage in Release builds, see `preconditionFailure(_:file:line:)`.
///
/// * In playgrounds and -Onone builds (the default for Xcode's Debug
/// configuration), stop program execution in a debuggable state after
/// printing `message`.
///
/// * In -O builds, has no effect.
///
/// * In -Ounchecked builds, the optimizer may assume that this function is
/// never called. Failure to satisfy that assumption is a serious
/// programming error.
///
/// - Parameters:
/// - message: A string to print in a playground or `-Onone` build. The
/// default is an empty string.
/// - file: The file name to print with `message`. The default is the file
/// where `assertionFailure(_:file:line:)` is called.
/// - line: The line number to print along with `message`. The default is the
/// line number where `assertionFailure(_:file:line:)` is called.
@inlinable public func assertionFailure(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line)
和 assert()
稍有区别,不过相差不大,请读者根据注释自行理解吧
先决条件
你可以通过调用 precondition(_:_:file:line:)
函数来写先决条件。给这个函数传入表达式计算为 true
或 false
,如果条件的结果是 false
, 信息就会显示出来。
precondition(_:_:file:line:)
函数的官方定义如下:
/// Checks a necessary condition for making forward progress.
///
/// Use this function to detect conditions that must prevent the program from
/// proceeding, even in shipping code.
///
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug
/// configuration): If `condition` evaluates to `false`, stop program
/// execution in a debuggable state after printing `message`.
///
/// * In `-O` builds (the default for Xcode's Release configuration): If
/// `condition` evaluates to `false`, stop program execution.
///
/// * In `-Ounchecked` builds, `condition` is not evaluated, but the optimizer
/// may assume that it *always* evaluates to `true`. Failure to satisfy that
/// assumption is a serious programming error.
///
/// - Parameters:
/// - condition: The condition to test. `condition` is not evaluated in
/// `-Ounchecked` builds.
/// - message: A string to print if `condition` is evaluated to `false` in a
/// playground or `-Onone` build. The default is an empty string.
/// - file: The file name to print with `message` if the precondition fails.
/// The default is the file where `precondition(_:_:file:line:)` is
/// called.
/// - line: The line number to print along with `message` if the assertion
/// fails. The default is the line number where
/// `precondition(_:_:file:line:)` is called.
public func precondition(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line)
从注释中不难看出precondition()
与 assert()
接受的函数参数都是一样的,例如:
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")
与 assertionFailure(_:file:line:)
函数相似,如果错误已经发生,你可以使用 preconditionFailure(_:file:line:)
函数来标明错误发生了并打印出相关信息。
preconditionFailure(_:file:line:)
函数的官方定义如下:
/// Indicates that a precondition was violated.
///
/// Use this function to stop the program when control flow can only reach the
/// call if your API was improperly used. This function's effects vary
/// depending on the build flag used:
///
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug
/// configuration), stops program execution in a debuggable state after
/// printing `message`.
///
/// * In `-O` builds (the default for Xcode's Release configuration), stops
/// program execution.
///
/// * In `-Ounchecked` builds, the optimizer may assume that this function is
/// never called. Failure to satisfy that assumption is a serious
/// programming error.
///
/// - Parameters:
/// - message: A string to print in a playground or `-Onone` build. The
/// default is an empty string.
/// - file: The file name to print with `message`. The default is the file
/// where `preconditionFailure(_:file:line:)` is called.
/// - line: The line number to print along with `message`. The default is the
/// line number where `preconditionFailure(_:file:line:)` is called.
public func preconditionFailure(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) -> Never
区别
从上文可以看出,断言和先决条件不论是使用情景还是使用方法都是极其相似的,那么他们到底有什么不一样呢?
其实它们最大的不同之处在于有效场景的不同:断言只在 debug 构建的时候检查,但先决条件则在 debug 和生产构建中生效。在生产构建中,断言中的条件不会被计算。这就是说你可以在开发的过程当中随便使用断言而无需担心影响生产性能。