Swift断言`asset` 与 先决条件`precondition`的使用和思考

Posted Jsen_Wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift断言`asset` 与 先决条件`precondition`的使用和思考相关的知识,希望对你有一定的参考价值。

Swift断言asset 与 先决条件precondition的使用和思考

断言 asset

###定义:

/// - 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)

用法:


func call2(_ phone: String) 
	 // 如果phone是11位的,就正常向下执行,如果不是,则阻断流程,打印错误信息
    assert(phone.count == 11, "Wrong Phone!")
    print("calling" + phone)


call2("18600722414") // 正常执行
call2("186") // 报错,并打印调用栈信息和message

在Assert源码文件中,还有一个与之对应的方法

/// - 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)

这个方法没有判断条件,而是用方法名告诉我们,这就是失败断言直接抛出错误用的,我们可以这样用

func call2(_ phone: String) 
    if phone.count != 11 
        assertionFailure("Wrong Phone!")
    
    
    print("calling" + phone)

call2("123") // 报错,并打印调用栈信息和message

所以这只相当于我们自己动手来实现低错误处罚的时机而已.本质是和assert方法一样的.

先决条件precondition

定义

/// - 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)

单看定义来说好像和assert基本是一样的.本着存在即合理的角度,我们先不追究区别,先看看用法:

func call(_ phone: String) 
	// 如果phone的位数为11,则正常执行,若不是则阻断流程,并报错
    precondition(phone.count == 11, "Wrong Phone!")
    print("calling" + phone)


call("18600722414") // 正常执行
call("123") // // 报错,并打印调用栈信息和message

这么一看,不但作用一样,甚至用法也一样,更甚者,还有一个

@inlinable public func assertionFailure(_ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line)

方法,对标assertionFailure方法,并且用法和表现也相同.

问题来了,为什么要弄两个一样功能的方法呢?

显然,这个问题是是不成立的,因为他们倆肯定不一样,
断言Assert仅在调试环境运行,
先决条件precondition则在调试环境和生产环境中运行。
这是至关重要的区别,可根据自己的需求而定.

看完源码学到的东西

@autoclosure

实战说话:

假设我们定一个方法,此方法需要传入一个()->T的闭包作为参数

func test(_ param: () -> String) 
    print(param())

那么他的调用方式就是

test  () -> String in
    return "wxs"

这个代码看起来是不是有点乱,尾随闭包的简写,方法名直接跟大括号,即便有多个参数,也会是很难看和难以理解的一种表达方式,所以苹果提供了@autoclosure

经过优化后我们可以写成

// 相较于上边的定义方式,仅仅只加入了一个关键词
func test2(_ param: @autoclosure () -> String) 
    print(param())

但是调用时的效果却非常不同

test2("wxs")

这样是不是清爽了许多,但是这样需要我们阅读方法的定义才能知道传入的"wxs"是作为一个闭包传入的,而不是字符串,这里边还可以传入表达式,比如

test2("wxs" + "wxs")

在舒爽的同时,他还不是那么强大,目前只支持()->T这样的无参数闭包

#file #line #function

这三个标示是为了方便获取代码执行时所在的文件,行数,具体方法的信息.
assertprecondition的方法中我们只见到了#file #line,我们先看一下效果

正如图中红框所示,断言报错后,可以获取断言所在的文件和位置信息.

我们再自己写一个使用#function的demo:

func call3(_ file: StaticString = #file, function: StaticString = #function, line: Int = #line) 
    print("file:\\(file)\\n function:\\(function)\\n line:\\(line)")


call3()

//print:
file:MyPlayground.playground
function:__lldb_expr_12
line:37

总结

1, asset只在debug触发,precondition debug/release都可以触发,可根据业务需要选择,但尽量使用precondition,因为这样可以debug和release表现一致,相信代码严谨度应该会有很高的提升.
2,@autoclosure是一个高度提高代码整洁性的标示,()->T类的闭包参数都可使用
3,#file #line #function可在日志类函数提供极大便利.

以上是关于Swift断言`asset` 与 先决条件`precondition`的使用和思考的主要内容,如果未能解决你的问题,请参考以下文章

swift 在Swift中测试前置条件(或断言)

Swift编程语言学习1.7——断言

Swift之:断言(Assertions)

Swift入门——可选类型(Optionals)与断言(Assert)

Swift入门——可选类型(Optionals)与断言(Assert)

Xcode 5 Asset Catalog 是不是向后兼容 pre-iOS 7?