Assert in Swift

Swift中断言的种类

condition -Onone(Debug) -O(Release) -Ounchecked Useage
assert 条件为假时,打印信息并终止 无影响 不执行,但优化器默认条件为真 测试时使用
assertionFailure 打印信息并终止 无影响 不执行,但优化器默认条件为真 测试时使用,提示条件不满足
precondition 条件为假时,打印信息并终止 条件为假时,终止程序 不执行,但优化器默认条件为真 若条件不满足,则产生严重的程序错误 检查条件,以决定是否继续执行
preconditionFailure 印信息并终止 终止程序 优化器默认永不执行;若条件不满足,则产生严重的程序错误 提示违反了前提条件
fatalError 无条件输出信息并终止程序 无条件输出信息并终止程序 无条件输出信息并终止程序
*说明:Xcode7.1中,-Ounchecked已经替换成-O -whole-module-optimization

Assert 定义

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

@autoclosure的作用在于当函数参数是一个不带参数的函数类型(即参数是一个不带参数的闭包类型)时,使用该关键字后,调用此函数时可以简化参数的写法,具体的看例子:

 func f(@autoclosure value: () -> Int) {
    print(value())
}
f(42)

如果没有autoclosure,则:

 func f(value: () -> Int) {
    print(value())
}
f({42})

这样做的目的不仅仅是为了简化写法活着调用,主要是为了实现参数的懒执行(Lazy Evaluation of Parameter)。举个&&的例子: 1 < 2 && expression() == true。 这种情况下,左边的执行完后,右边表示中expression()都没有必要去执行了。要实现这个目的,那么需有实现形如:

func &&(a: Bool, @autoclosure b: () -> Bool) -> Bool {
    if a {
        if b() {
            return true
        }
    }
    return false
}

代码优化

在不同的情况下,上述断言会被优化。换言之,代码会被移除。在C中,assert是宏定义,代码编译的时候宏展开替换代码。而Swift中没有宏的概念,为了实现同样的目的,assert等函数前声明:@_transparent,这样在实际调用assert的时候,可以类似宏一样插入展开。那根据一般的概念,.lib/.a/.so的库都无法做到将函数的实现“插入”进调用的代码部分。这里引出Swift的标准库,该库是.swiftmodule文件,该标准库包含了所有声明和具体的“实现”。对于属性_transparent,在标准库中是"SIL block"的形式,在实际使用中可以把函数的具体实现导入进调用代码中。这样在实际调用assert的时候,可以类似宏一样插入展开。

参考:

https://www.mikeash.com/pyblog/friday-qa-2016-03-04-swift-asserts.html https://github.com/apple/swift/blob/0619e57a61f27f721e273ab6f808ac81011aeb2c/stdlib/public/core/Assert.swift https://developer.apple.com/swift/blog/?id=4