ios Swift:测试 nil 的可选项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25097727/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:39:44  来源:igfitidea点击:

Swift: Testing optionals for nil

iosswiftoptional

提问by tng

I'm using Xcode 6 Beta 4. I have this weird situation where I cannot figure out how to appropriately test for optionals.

我正在使用 Xcode 6 Beta 4。我遇到了这种奇怪的情况,我无法弄清楚如何适当地测试可选项。

If I have an optional xyz, is the correct way to test:

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

if (xyz) // Do something

or

或者

if (xyz != nil) // Do something

The documents say to do it the first way, but I've found that sometimes, the second way is required, and doesn't generate a compiler error, but other times, the second way generates a compiler error.

文档说用第一种方式做,但我发现有时需要第二种方式,并且不会产生编译器错误,但有时,第二种方式会产生编译器错误。

My specific example is using the GData XML parser bridged to swift:

我的具体示例是使用桥接到 swift 的 GData XML 解析器:

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

if (xmlError != nil)

Here, if I just did:

在这里,如果我只是这样做:

if xmlError

it would always return true. However, if I do:

它总是会返回 true。但是,如果我这样做:

if (xmlError != nil)

then it works (as how it works in Objective-C).

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

Is there something with the GData XML and the way it treats optionals that I am missing?

GData XML 以及它处理我缺少的选项的方式有什么问题吗?

回答by ktzhang

In Xcode Beta 5, they no longer let you do:

在 Xcode Beta 5 中,它们不再允许您执行以下操作:

var xyz : NSString?

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

This produces an error:

这会产生一个错误:

does not conform to protocol 'BooleanType.Protocol'

不符合协议“BooleanType.Protocol”

You have to use one of these forms:

您必须使用以下形式之一:

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

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

回答by zevij

To add to the other answers, instead of assigning to a differently named variable inside of an ifcondition:

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

var a: Int? = 5

if let b = a {
   // do something
}

you can reuse the same variable name like this:

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

var a: Int? = 5

if let a = a {
    // do something
}

This might help you avoid running out of creative variable names...

这可能会帮助您避免用完创意变量名称...

This takes advantage of variable shadowingthat is supported in Swift.

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

回答by Isaac Drachman

One of the most direct ways to use optionals is the following:

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

Assuming xyzis of optional type, like Int?for example.

假设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
}

This way you can both test if xyzcontains a value and if so, immediately work with that value.

通过这种方式,您可以测试是否xyz包含一个值,如果包含,则立即使用该值。

With regards to your compiler error, the type UInt8is not optional (note no '?') and therefore cannot be converted to nil. Make sure the variable you're working with is an optional before you treat it like one.

关于您的编译器错误,该类型UInt8不是可选的(注意没有“?”),因此无法转换为nil. 在将其视为一个变量之前,请确保您正在使用的变量是一个可选变量。

回答by Fangming

Swift 3.0, 4.0

斯威夫特 3.0、4.0

There are mainly two ways of checking optional for nil. Here are examples with comparison between them

主要有两种方式检查 optional 是否为 nil。以下是它们之间的比较示例

1. if let

1.如果让

if letis the most basic way to check optional for nil. Other conditions can be appended to this nil check, separated by comma. The variable must not be nil to move for the next condition. If only nil check is required, remove extra conditions in the following code.

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

Other than that, if xis not nil, the if closure will be executed and x_valwill be available inside. Otherwise the else closure is triggered.

除此之外,如果x不是 nil,则 if 闭包将被执行并x_val在内部可用。否则触发 else 闭包。

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

}

2. guard let

2.守护让

guard letcan do similar things. It's main purpose is to make it logically more reasonable. It's like saying Make sure the variable is not nil, otherwise stop the function. guard letcan also do extra condition checking as if let.

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

The differences are that the unwrapped value will be available on same scope as guard let, as shown in the comment below. This also leads to the point that in else closure, the program has to exit the current scope, by return, break, etc.

不同之处在于解包的值将在与 相同的范围内可用guard let,如下面的评论所示。这也导致在其他封闭,该程序必须退出当前范围来看,通过returnbreak等等。

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

回答by codester

From swift programming guide

来自 swift 编程指南

If Statements and Forced Unwrapping

You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false.

If 语句和强制解包

您可以使用 if 语句来确定一个可选项是否包含一个值。如果一个可选项确实有一个值,它的计算结果为真;如果它根本没有价值,则评估为假。

So the best way to do this is

所以最好的方法是

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

and if you are using the xyzin if statement.Than you can unwrap xyzin if statement in constant variable .So you do not need to unwrap every place in if statement where xyzis used.

并且如果您使用xyzin if 语句。那么您可以xyz在常量变量中的 if 语句中解包。因此,您不需要解包 if 语句中xyz使用的每个地方。

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

This convention is suggested by appleand it will be followed by devlopers.

这个约定是由开发人员建议的,apple并且会被开发人员遵循。

回答by Chris Frederick

Although you must still either explicitly compare an optional with nilor use optional binding to additionally extract its value (i.e. optionals are not implicitly converted into Boolean values), it's worth noting that Swift 2 has added the guardstatementto help avoid the pyramid of doomwhen working with multiple optional values.

尽管您仍然必须显式地将可选项与nil或使用可选项绑定来额外提取其值(即选项不会隐式转换为布尔值),但值得注意的是,Swift 2 已添加该guard语句以帮助避免工作时出现厄运金字塔具有多个可选值。

In other words, your options now include explicitly checking for nil:

换句话说,您现在的选择包括明确检查nil

if xyz != nil {
    // Do something with xyz
}

Optional binding:

可选绑定:

if let xyz = xyz {
    // Do something with xyz
    // (Note that we can reuse the same variable name)
}

And guardstatements:

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

Note how ordinary optional binding can lead to greater indentation when there is more than one optional value:

请注意,当有多个可选值时,普通的可选绑定如何导致更大的缩进:

if let abc = abc {
    if let xyz = xyz {
        // Do something with abc and xyz
    }        
}

You can avoid this nesting with guardstatements:

您可以使用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

回答by Brody Robertson

Swift 5 Protocol Extension

Swift 5 协议扩展

Here is an approach using protocol extension so that you can easily inline an optional nil check:

这是一种使用协议扩展的方法,以便您可以轻松内联可选的 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

    }

}

Usage

用法

var myValue: String?

if myValue.isNil {
    // do something
}

if myValue.isSome {
    // do something
}

回答by Tiago

Another approach besides using ifor guardstatements to do the optional binding is to extend Optionalwith:

除了使用iforguard语句进行可选绑定之外,另一种方法是扩展Optional

extension Optional {

    func ifValue(_ valueHandler: (Wrapped) -> Void) {
        switch self {
        case .some(let wrapped): valueHandler(wrapped)
        default: break
        }
    }

}

ifValuereceives a closure and calls it with the value as an argument when the optional is not nil. It is used this way:

ifValue接收一个闭包并在可选值不为 nil 时使用该值作为参数调用它。它是这样使用的:

var helloString: String? = "Hello, World!"

helloString.ifValue {
    print(
if let _ = xyz {
    // something that should only happen if xyz is not nil
}
) // prints "Hello, World!" } helloString = nil helloString.ifValue { print(
func f(x: String?) -> String {
    return x == nil ? "empty" : "non-empty"
}
) // This code never runs }

You should probably use an ifor guardhowever as those are the most conventional (thus familiar) approaches used by Swift programmers.

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

回答by Ben Lachman

One option that hasn't specifically been covered is using Swift's ignored value syntax:

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

##代码##

I like this since checking for nilfeels out of place in a modern language like Swift. I think the reason it feels out of place is that nilis basically a sentinel value. We've done away with sentinels pretty much everywhere else in modern programming so nilfeels like it should go too.

我喜欢这个,因为nil在像 Swift 这样的现代语言中检查感觉不合适。我认为它感觉不合适的原因nil基本上是一个哨兵值。在现代编程中,我们几乎在所有其他地方都取消了哨兵,所以nil感觉也应该这样做。

回答by qed

Instead of if, ternary operator might come handy when you want to get a value based on whether something is nil:

相反的if,当你要根据东西是否是零得到一个值三元运营商可能来方便:

##代码##