理解 ?和 !在 swift - 具体情况

Understanding ? and ! in swift - Specific case

我从swift和iOS开始,我遇到了一个疑问。让我们看看,有这个特定的源代码:

if object?.stringValue != nil {
    // send it to server
    session.stopRunning()
    sendQRCodeToApiServer(stringValueObtained: (object?.stringValue)!)
}

我知道在 if object?.stringValue != nil 中? character 意味着对象 var 可以是 nil,所以它是一个可选的。但是在内部行中:

sendQRCodeToApiServer(stringValueObtained: (object?.stringValue)!)

如果我不解开object?.stringValue in () 并带有感叹号(!),解释器会抛出一个错误,那(如果我理解得很好)意味着你确定结果有一个值并且它具有所需的类型,我的意思是,object.stringValue 有一个值并且它是一个字符串。

好吧,我完全理解,但是编译器这么说?和 !是必需的,首先说可能有一个值,其次说肯定有一个值,.......

我觉得这个语法不一致且令人困惑,谁能解释一下?

非常感谢您的宝贵时间

语法强制展开一个可选的链式表达式 object?.stringValue。因为你不能写 object?.stringValue! 因为 stringValue 的结果不是可选的所以你添加了括号 (object?.stringValue)!

不幸的是,编译器建议语法,尽管它实际上与 object!.stringValue 完全相同,这在您的情况下完全没问题,因为 object 在检查后绝对不是 nil

将其与 'if let'

的可选绑定一起使用
if let stringVal = object?.stringValue {
    // send it to server
    session.stopRunning()
    sendQRCodeToApiServer(stringValueObtained: stringVal)
}

总是当你使用可选链接时,然后使用 if let 绑定,因为可选链接总是 return 一个可选值,无论该值容器的声明是否意味着对象是非可选的。

if object?.stringValue != nil 只被选中,没有被选中。 因此,您需要展开价值。 推荐使用此代码。 if let stringValue = object?.stringValue { session.stopRunning() sendQRCodeToApiServer(stringValueObtained: stringValue) }

 sendQRCodeToApiServer(stringValueObtained: (object?.stringValue)!)

在这一行中,编译器提示您解包,因为函数 "stringValueObtained" 需要一个非空值作为参数。如果您将函数的参数更改为可选参数,它不会提示您解包。 希望对你有帮助。

首先,让我们检查一下:

if object?.stringValue != nil {

如果 object 为 nil 或 stringValue 为 nil,条件将为 false。那是 objects?.whatEver 将 return nil 如果 object 为 nil,object?.stringValue 将 return nil 如果 stringValue 为 nil.

sendQRCodeToApiServer(stringValueObtained: (object?.stringValue)!)

sendQRCodeToApiServer 需要一个字符串,但是 object?.stringValue return 一个 String? 所以你需要解包。因为有 if 条件,所以在这里展开是安全的。通过 object!.stringValue (unwrap object) 或 (object?.stringValue)! - 打开 returned 值。

更好的选择是在 if 条件下展开:

if let stringVal = object?.stringValue {
    // send it to server
    session.stopRunning()
    sendQRCodeToApiServer(stringValueObtained: stringVal)
}

可选性/强制展开/可选链接可能会非常混乱。

根据经验,如果您发现必须强制解包变量 'unexpectedly',那么绝对值得重新访问代码以故意解包您希望访问的变量。

有些人可能会说“每次你使用 ! 时,小独角兽就会死去(可怕地)

在你的第一行代码中,对象是可选的

if object?.stringValue != nil {

除非您专门解包对象,否则您必须使用 ?每当您访问它或它的成员时。这就是为什么当您稍后在 sendQRCodeToApiServer 的方法调用中再次访问它时,您必须再次打开它。

当您解包一个可选变量时,您为变量的解包版本指定的名称就像该范围内的任何其他变量一样工作。另外,当您打开一个可选的包装时,请记住您正在积极减少 ?和 !出现在你的代码中,所以你真的在 6 个月的时间里让你自己或下一个看到你的代码的开发人员更易读和理解(嘿,独角兽爱你)。

让我们专门解包您希望使用的唯一变量(如果您有很多行访问对象成员的代码,那么我们可以解包对象 - 但让我们坚持使用您的代码示例)

if let stringValueObtained = object?.stringValue {
    // send it to server
    session.stopRunning()
    sendQRCodeToApiServer(stringValueObtained: stringValueObtained)
}

注:

  • 超出if语句范围stringValueObtained不存在

  • 我专门为解包的变量命名了它的预期用途