Swift: 测试可选项为 nil

我用的是 Xcode 6 Beta 4。我遇到了一个奇怪的情况,我不知道如何适当地测试可选项。

如果我有一个可选的 xyz,这是测试的正确方法:

if (xyz) // Do something

或者

if (xyz != nil) // Do something

文档说要用第一种方法,但是我发现有时候,第二种方法是必需的,不会产生编译器错误,但是有时候,第二种方法会产生编译器错误。

我的具体例子是使用 GData XML 解析器进行快速桥接:

let xml = GDataXMLDocument(
XMLString: responseBody,
options: 0,
error: &xmlError);


if (xmlError != nil)

在这里,如果我这样做:

if xmlError

它总是返回真值,但是,如果我这样做:

if (xmlError != nil)

然后它工作(就像它在 Objective-C 中的工作方式一样)。

GData XML 和它处理可选项的方式有什么我不知道的地方吗?

217265 次浏览
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.")     }

这个测试在所有情况下都如预期般有效。 顺便说一下,你不需要括号 ()

使用可选项的最直接方法之一是:

假设 xyz是可选类型,例如 Int?

if let possXYZ = xyz {
// do something with possXYZ (the unwrapped value of xyz)
} else {
// do something now that we know xyz is .None
}

这样,您既可以测试 xyz是否包含值,如果包含,则立即使用该值。

关于编译器错误,类型 UInt8不是可选的(注意,不是’?’)因此不能转换成 nil。确保您正在处理的变量是可选的,然后再将其视为可选变量。

来自快速编程 向导

如果语句和强制展开

可以使用 if 语句查找可选项是否包含 如果一个可选项确实有一个值,它的计算结果为 true; 如果 没有任何值,则计算结果为 false。

所以最好的办法就是

// swift > 3
if xyz != nil {}

如果在 if 语句中使用 xyz。然后可以在常量变量的 if 语句中展开 xyz。因此,不需要在使用 xyz的 if 语句中取消每个位置的换行。

if let yourConstant = xyz {
//use youtConstant you do not need to unwrap `xyz`
}

这个约定是由 apple提出的,开发人员也将遵循这个约定。

在 Xcode Beta 5中,他们不再允许你这样做:

var xyz : NSString?


if xyz {
// Do something using `xyz`.
}

这会产生一个错误:

不符合「 BooleType.Protocol 」协议

你必须使用以下表格之一:

if xyz != nil {
// Do something using `xyz`.
}


if let xy = xyz {
// Do something using `xy`.
}

要添加到其他答案,而不是在 if条件中赋予一个名称不同的变量:

var a: Int? = 5


if let b = a {
// do something
}

您可以像下面这样重用相同的变量名:

var a: Int? = 5


if let a = a {
// do something
}

这可以帮助您避免用尽创造性的变量名..。

这利用了 Swift 支持的 可变阴影

现在你可以迅速地做下面的事情,让你重新获得一点点的目标-c if nil else

if textfieldDate.text?.isEmpty ?? true {


}

尽管您仍然必须显式地将可选项与 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
// e.g. 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

当您想要根据某个值是否为零来获取值时,三元运算符可能比 if更方便:

func f(x: String?) -> String {
return x == nil ? "empty" : "non-empty"
}

如果你有条件,并且想要展开和比较,那么利用复合布尔表达式的短路求值如何呢

if xyz != nil && xyz! == "some non-nil value" {


}

当然,这并不像其他一些建议的文章那样可读,但是它完成了工作,并且比其他建议的解决方案更加简洁。

Swift 3.04.0

检查可选是否为 nil 主要有两种方法

1

if let是检查可选 nil 的最基本方法。其他条件可以附加到这个用逗号分隔的 nil 检查中。要在下一个条件下移动变量,该变量不能为空。如果只需要 nil 检查,请删除下面代码中的额外条件。

除此之外,如果 x不是 null,那么将执行 if 闭包,并且 x_val将在其中可用。否则将触发 else 闭包。

if let x_val = x, x_val > 5 {
//x_val available on this scope
} else {


}

2. 警卫出租

guard let可以做类似的事情。它的主要目的是使它在逻辑上更加合理。这就像说 确保变量不是 nil,否则停止函数guard let还可以像 if let一样执行额外的条件检查。

区别在于,取消包装的值将在与 guard let相同的作用域上可用,如下面的注释所示。这也导致在 else 闭包中,程序必须通过 returnbreak等退出当前作用域。

guard let x_val = x, x_val > 5 else {
return
}
//x_val available on this scope

除了使用 ifguard语句执行可选绑定之外,另一种方法是使用以下方法扩展 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
}

不过,您可能应该使用 ifguard,因为它们是 Swift 程序员使用的最传统(因此也是最熟悉的)方法。

一个没有被特别提及的选项是使用 Swift 忽略的值语法:

if let _ = xyz {
// something that should only happen if xyz is not nil
}

我喜欢这个,因为检查 nil感觉不适合在一个现代语言,如斯威夫特。我认为它感觉不合适的原因是 nil基本上是一个哨兵值。在现代编程中,我们几乎在其他任何地方都消除了哨兵,所以 nil觉得它也应该消失。

可以选择

你也可以使用 Nil-Coalescing Operator

如果包含 a值,则 nil-coalescing operator(a ?? b)打开一个可选的 a; 如果 anil,则返回 a默认值 b。表达式 a 总是可选类型。表达式 b必须与存储在 a中的类型匹配。

let value = optionalValue ?? defaultValue

如果 optionalValuenil,它会自动赋值给 defaultValue

Swift 5协议扩展

下面是一种使用协议扩展的方法,这样您就可以轻松地内联一个可选的 nil 检查:

import Foundation


public extension Optional {


var isNil: Bool {


guard case Optional.none = self else {
return false
}


return true


}


var isSome: Bool {


return !self.isNil


}


}

用法

var myValue: String?


if myValue.isNil {
// do something
}


if myValue.isSome {
// do something
}

如果有人也尝试查找工作与字典和尝试工作与可选(无)。

 let example : [Int:Double?] = [2: 0.5]
let test = example[0]

你最后会变成双重人格。

要继续编写代码,只需使用合并来绕过它。

 let example : [Int:Double?] = [2: 0.5]
let test = example[0] ?? nil

现在你只有双倍了?

这完全合乎逻辑,但我找错了地方,也许能帮到别人。

自从 Swift 5.7:

if let xyz {
// Do something using `xyz` (`xyz` is not optional here)
} else {
// `xyz` was nil
}