我正在使用 Xcode 6 Beta 4。我遇到了这种奇怪的情况,我无法弄清楚如何适当地测试选项。
如果我有一个可选的 xyz,那么正确的测试方法是:
if (xyz) // Do something
或者
if (xyz != nil) // Do something
文件说要采用第一种方式,但我发现有时需要第二种方式,并且不会产生编译器错误,但其他时候,第二种方式会产生编译器错误。
我的具体示例是使用桥接到 swift 的 GData XML 解析器:
let xml = GDataXMLDocument(
XMLString: responseBody,
options: 0,
error: &xmlError);
if (xmlError != nil)
在这里,如果我只是这样做:
if xmlError
它总是会返回 true。但是,如果我这样做:
if (xmlError != nil)
然后它就可以工作了(就像它在 Objective-C 中的工作方式一样)。
GData XML 以及它处理我缺少的选项的方式有什么问题吗?
在 Xcode Beta 5 中,它们不再允许您这样做:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
这会产生一个错误:
不符合协议'BooleanType.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 支持的 variable shadowing。
使用选项的最直接方法之一如下:
假设 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
。在将其视为一个变量之前,请确保您正在使用的变量是一个可选变量。
斯威夫特 3.0、4.0
主要有两种检查可选项是否为 nil 的方法。以下是它们之间的比较示例
1.如果让
if let
是检查可选项是否为 nil 的最基本方法。其他条件可以附加到这个 nil 检查,用逗号分隔。变量不能为 nil 才能移动到下一个条件。如果只需要 nil 检查,请删除以下代码中的额外条件。
除此之外,如果 x
不为零,则将执行 if 闭包并且 x_val
将在内部可用。否则触发 else 闭包。
if let x_val = x, x_val > 5 {
//x_val available on this scope
} else {
}
2.守护让
guard let
可以做类似的事情。它的主要目的是使它在逻辑上更合理。这就像说确保变量不为零,否则停止函数。 guard let
还可以像 if let
一样进行额外的条件检查。
不同之处在于展开的值将在与 guard let
相同的范围内可用,如下面的评论所示。这也导致在 else 闭包中,程序必须通过 return
、break
等退出当前范围。
guard let x_val = x, x_val > 5 else {
return
}
//x_val available on this scope
来自 swift 编程guide
If 语句和强制解包 您可以使用 if 语句来查明可选项是否包含值。如果一个可选项确实有一个值,它的计算结果为真;如果它根本没有价值,它的评估结果为假。
所以最好的方法是
// swift > 3
if xyz != nil {}
如果您在 if 语句中使用 xyz
。那么您可以在常量变量中的 if 语句中解开 xyz
。因此您不需要解开 if 语句中使用 xyz
的每个地方。
if let yourConstant = xyz {
//use youtConstant you do not need to unwrap `xyz`
}
apple
建议使用此约定,开发人员将遵循此约定。
if xyz != nil {...}
。
尽管您仍然必须显式地将可选项与 nil
进行比较,或者使用可选项绑定来额外提取其值(即,可选项不会隐式转换为布尔值),但值得注意的是 Swift 2 添加了 guard
statement 来帮助避免pyramid of doom 使用多个可选值时。
换句话说,您的选项现在包括显式检查 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
nil
值,但我同意学习曲线有点陡峭。 :)
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
}
pythonistas
的 swift
类似物,它试图使语言保持某种形式的 Pythonic 纯度。我的看法?我刚刚将您的代码提升到我的 Utils mixin 中。
没有特别提到的一种选择是使用 Swift 的忽略值语法:
if let _ = xyz {
// something that should only happen if xyz is not nil
}
我喜欢这样,因为在 Swift 这样的现代语言中检查 nil
感觉格格不入。我认为它感觉不合适的原因是 nil
基本上是一个哨兵值。在现代编程中,我们几乎在其他任何地方都取消了哨兵,所以 nil
感觉也应该这样做。
当您想根据某物是否为 nil 来获取值时,三元运算符可能会派上用场,而不是 if
:
func f(x: String?) -> String {
return x == nil ? "empty" : "non-empty"
}
xyz == nil
表达式不起作用,但 x != nil
有效。不知道为什么。
除了使用 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 程序员使用的最传统(因此很熟悉)的方法。
可选的
您也可以使用 Nil-Coalescing Operator
nil-coalescing 运算符 (a ?? b) 如果可选 a 包含一个值,则解包它,如果 a 为 nil,则返回默认值 b。表达式 a 始终是可选类型。表达式 b 必须匹配存储在 a 中的类型。
let value = optionalValue ?? defaultValue
如果 optionalValue
是 nil
,它会自动将值分配给 defaultValue
现在您可以快速执行以下操作,让您重新获得一点目标-c if nil else
if textfieldDate.text?.isEmpty ?? true {
}
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.") }
该测试在所有情况下都按预期工作。顺便说一句,您不需要括号 ()
。
if (xyz != nil)
。
如果您有条件并且想要展开和比较,那么如何利用复合布尔表达式的短路评估,如
if xyz != nil && xyz! == "some non-nil value" {
}
当然,这不像其他一些建议的帖子那样可读,但可以完成工作并且比其他建议的解决方案更简洁。
如果有人也尝试使用字典并尝试使用 Optional(nil)。
let example : [Int:Double?] = [2: 0.5]
let test = example[0]
你最终会得到 Double?? 类型。
要继续处理您的代码,只需使用合并来绕过它。
let example : [Int:Double?] = [2: 0.5]
let test = example[0] ?? nil
现在你只有双?
这完全合乎逻辑,但我搜索了错误的东西,也许它可以帮助别人。