Swift:testing可选项为零
我正在使用Xcode 6 Beta 4.我有这种奇怪的情况,我不知道如何适当地testingoptionals。
如果我有一个可选的xyz,是testing的正确方法:
if (xyz) // Do something
要么
if (xyz != nil) // Do something
文件说,这是第一种方式,但我发现,有时,第二种方法是必需的,不会产生编译器错误,但有时,第二种方式会产生编译器错误。
我的具体例子是使用桥接到swift的GData XMLparsing器:
let xml = GDataXMLDocument( XMLString: responseBody, options: 0, error: &xmlError); if (xmlError != nil)
在这里,如果我只是这样做:
if xmlError
它总是会返回true。 但是,如果我这样做:
if (xmlError != nil)
那么它的工作原理(如何在Objective-C中工作)。
GData XML和它对待我缺less的可选项的方法有什么?
在Xcodetesting版5,他们不再让你这样做
var xyz : NSString? if xyz { //Do Something }
产生一个错误"does not conform to protocol 'BooleanType.Protocol'"
你必须做这些陈述之一:
if xyz != nil { //Do Something } if let xy = xyz { //Do Something }
使用可选项的最直接的方法之一是:
假设xyz
是可选types,如Int?
例如。
if let possXYZ = xyz { // do something with possXYZ (the unwrapped value of xyz) } else { // do something now that we know xyz is .None }
这样你可以testingxyz
包含一个值,如果是的话,立即使用该值。
关于编译器错误, UInt8
types不是可选的(注意不是“?”),因此不能转换为nil
。 在对待它之前,确保你正在使用的variables是可选的。
要添加到其他答案中,而不是在if
条件中分配一个不同名称的variables:
var a: Int? = 5 if let b = a { // do something }
你可以像这样重用相同的variables名称:
var a: Int? = 5 if let a = a { // do something }
这可以帮助您避免用完创意variables名称…
这利用了Swift支持的可变阴影 。
从迅速的编程指南
如果陈述和强制解包
您可以使用if语句来确定可选是否包含值。 如果一个可选项有一个值,则它的计算结果为true; 如果它没有任何价值,那么它的评价是错误的。
所以最好的办法是
// swift > 3 if xyz != nil {}
如果你在if语句中使用xyz
。那么你可以在常量variables的if语句中解开xyz
。所以你不需要在if语句中使用xyz
地方解开每一个地方。
if let yourConstant = xyz{ //use youtConstant you do not need to unwrap `xyz` }
这个惯例是由apple
提出的,接下来是开发者。
虽然你仍然必须显式比较一个可选的nil
或者使用可选的绑定来额外提取它的值(也就是说,可选项并不隐式转换为布尔值),但值得注意的是Swift 2已经添加了guard
语句来帮助避免厄运当使用多个可选值时。
换句话说,你的选项现在包括显式检查nil
:
if xyz != nil { // Do something with xyz }
可选绑定:
if let xyz = xyz { // Do something with xyz // (Note that we can reuse the same variable name) }
和guard
声明:
guard let xyz = xyz else { // Handle failure and then exit this code block // eg by calling return, break, continue, or throw return } // Do something with xyz, which is now guaranteed to be non-nil
请注意,如果有多个可选值,普通的可选绑定会导致更大的缩进:
if let abc = abc { if let xyz = xyz { // Do something with abc and xyz } }
你可以用guard
语句来避免这种嵌套:
guard let abc = abc else { // Handle failure and then exit this code block return } guard let xyz = xyz else { // Handle failure and then exit this code block return } // Do something with abc and xyz
Swift 3.0,4.0
主要有两种检查可选项的方法。 这里是他们之间比较的例子
如果让
if let
是检查可选的最基本的方式为零。 其他条件可以附加到这个零检查,用逗号分隔。 在下一个条件下,variables不能为零。 如果只需要零检查,请删除以下代码中的额外条件。
除此之外,如果x
不为零,则将执行if闭包,并且x_val
将在内部可用。 否则就会触发else闭包。
if let x_val = x, x_val > 5 { //x_val available on this scope } else { }
2.后卫让
guard let
可以做类似的事情。 主要目的是使其在逻辑上更合理。 这就像说确保variables不是零,否则停止function 。 guard let
也可以做额外的条件检查。
不同的是,展开后的值将在与guard let
相同的范围内可用,如下面的注释所示。 这也导致在其他的closures中,程序必须退出当前范围,通过return
, break
等。
guard let x_val = x, x_val > 5 else { return } //x_val available on this scope
而不是if
,当你想要得到一个价值的基础上,三元运算符可能会得心应手:
func f(x: String?) -> String { return x == nil ? "empty" : "non-empty" }
var xyz : NSDictionary? // case 1: xyz = ["1":"one"] // case 2: (empty dictionary) xyz = NSDictionary() // case 3: do nothing if xyz { NSLog("xyz is not nil.") } else { NSLog("xyz is nil.") }
这个testing在所有情况下都按预期工作。 顺便说一句,你不需要括号()
。
现在你可以迅速做下面的事情, if nil else
事情,你可以重新获得一点目标
if textfieldDate.text?.isEmpty ?? true { }
如果你有条件,想打开和比较,如何利用复合布尔expression式的短路评估
if xyz != nil && xyz! == "some non-nil value" { }
当然,这不像其他一些build议的post那样可读,但是完成了这个工作,并且比其他build议的解决scheme稍微简洁一些。
除了使用if
或guard
语句来执行可选绑定之外,另一种方法是使用以下方法扩展Optional
:
extension Optional { func ifValue(_ valueHandler: (Wrapped) -> Void) { switch self { case .some(let wrapped): valueHandler(wrapped) default: break } } }
ifValue
接收一个闭包,并在可选参数不为nil时将其作为参数调用。 它是这样使用的:
var helloString: String? = "Hello, World!" helloString.ifValue { print($0) // prints "Hello, World!" } helloString = nil helloString.ifValue { print($0) // This code never runs }
你可能应该使用if
或者guard
因为那些是Swift程序员使用的最传统的方法。