Swift:测试nil的选项

时间:2014-08-02 17:39:02

标签: ios swift optional

我正在使用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的某些内容以及它对待我缺少的选项的方式?

14 个答案:

答案 0 :(得分:142)

在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`.
}

答案 1 :(得分:19)

要添加到其他答案,而不是在if条件内分配不同命名的变量:

var a: Int? = 5

if let b = a {
   // do something
}

您可以重复使用相同的变量名称:

var a: Int? = 5

if let a = a {
    // do something
}

这可以帮助您避免耗尽广告素材变量名称...

这利用了Swift支持的variable shadowing

答案 2 :(得分:18)

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

假设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 :(得分:13)

Swift 3.0,4.0

主要有两种方法可以检查nil的可选项。以下是它们之间进行比较的例子

<强> 1。如果让

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

除此之外,如果x不是nil,则将执行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

答案 4 :(得分:10)

来自swift编程guide

  

如果语句和强制解包

     

您可以使用if语句来确定可选项是否包含   值。如果可选项具有值,则计算结果为true;如果它   没有任何价值,它的评估结果为假。

所以最好的方法是

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

如果您在if语句中使用xyz。那么您可以在常量变量中的if语句中展开xyz。因此,您不需要在if语句中展开{{1使用。

xyz

此约定由if let yourConstant = xyz{ //use youtConstant you do not need to unwrap `xyz` } 建议,然后是devlopers。

答案 5 :(得分:8)

虽然您仍然必须明确地将可选项与nil进行比较,或者使用可选绑定来另外提取其值(即,选项不会隐式转换为布尔值),但值得注意的是Swift 2添加了{{ 3}}在处理多个可选值时帮助避免使用guard statement

换句话说,您的选项现在包括明确检查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

答案 6 :(得分:3)

而不是if,当你想根据某些东西是否为零来获取值时,三元运算符可能会派上用场:

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

答案 7 :(得分:2)

除了使用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程序员使用的最常规(熟悉)方法。

答案 8 :(得分:1)

一个尚未明确涵盖的选项是使用Swift的被忽略值语法:

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

我之所以喜欢这样,是因为检查nil在像Swift这样的现代语言中感觉不合适。我认为感觉不合时宜的原因是nil基本上是哨兵值。在现代编程中,我们几乎已经无处使用哨兵了,所以nil感觉也应该去。

答案 9 :(得分:1)

Swift 5协议扩展

这是一种使用协议扩展的方法,因此您可以轻松地内联可选的nil检查:

 public extension Optional {

    var isNil: Bool {

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

        return true

    }

}

用法

var myValue: String?

if !myValue.isNil {
    // do something
}

答案 10 :(得分:0)

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.")     }

此测试在所有情况下都按预期工作。 顺便说一句,您不需要括号()

答案 11 :(得分:0)

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

if textfieldDate.text?.isEmpty ?? true {

}

答案 12 :(得分:0)

如果您有条件且想要打开并进行比较,那么如何利用复合布尔表达式的短路评估,如

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

}

当然,这不像其他一些建议的帖子那样可读,但是比其他建议的解决方案完成工作并且有些简洁。

答案 13 :(得分:0)

您还可以使用Nil-Coalescing Operator

  

如果nil-coalescing operatora ?? b)包含可选的a值,则解开可选的a;如果{ {1}}是a。表达式a始终是可选类型。表达式b必须与a内部存储的类型匹配。

nil

如果ba,它将自动为let value = nullableValue ?? defaultValue 赋值