“明显地展开了财产”警告?

时间:2019-09-09 09:56:04

标签: swift swift5

我有一堂课,我有一个这样的属性:

var residenceId: Int!

使用Xcode 10和Swift 4.2进行构建时,没有问题。但是,在安装Xcode 11 Beta并转换为Swift 5之后,我得到以下警告:

Implicitly unwrapped property 'residenceId' declared here

稍后在课堂上我也有这个功能:

func jsonDictionary() -> [String : Any] {
    return ["residenceId": residenceId]
}

我在这里得到警告

Coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional

我们不再允许使用隐式展开的可选吗?

enter image description here

编辑:

更多研究之后,我开始相信“在这里声明的未包装属性'residenceId'”实际上不是警告,而是一些信息(以灰色标签而不是通常的黄色显示)可以提供帮助我明白为什么我会收到第二次警告。

为了澄清,我的问题是我们是否不再能够使用'!'属性上的符号定义一个隐式解开的属性(仅在我们确定它不会为nil时才明显),以便以后避免显式解开该属性(从而简化代码)。

1 个答案:

答案 0 :(得分:4)

从Swift 4开始,我们所知道的ImplicitlyUnwrappedOptional!变成了Optional

检查:

let a: ImplicitlyUnwrappedOptional<Int> = 1

会吐出错误:

  

“ ImplicitlyUnwrappedOptional”已重命名为“ Optional”

因此,如果我们这样做:

let a: Int! = 1
print(type(of: a)) //will print "Optional<Int>"

它仍然是Optional<Int>,但向编译器指示可以隐式解包。

  

隐式展开是声明的一部分。

     

...

     

!视为?的同义词,另外,它在声明上添加一个标志,让编译器知道声明的值可以隐式展开。
   Ref:Reimplementation of Implicitly Unwrapped Optionals


现在要回答主要问题:

如果您这样做:

let a: Int! = 1

let b: Any = a
print(type(of: b)) //prints "Optional<Int>"

它将给出以下警告:

  

表达式从'Int?'隐式强制。到“任何”

或根据Xcode 11

  

强制转换为'Int?'类型的隐式不可包装值设为“任何”不会解开可选

请注意,我们尝试从Any中获取非可选的Int?,这意味着我们基本上期待Int,但只需指定Any即可还解开Optional
它将保持为Optional ,这就是该警告的含义。


解决方案:

要优雅地处理此警告,我们可以执行以下任一操作:

let a: Int! = 1

let b: Any? = a
type(of: b) //Optional<Any>.Type

let c: Any! = a
type(of: c) //Optional<Any>.Type

let d: Any = a!
type(of: d) //Int.Type

编辑:(基于comment

  

!而不是?对程序员有什么实际区别?

!告诉编译器可以将其隐式解包,从而可以简化对可选链接的需求。

示例:

  • 使用?

    class A {
        var n: Int? = 1
    }
    
    class B {
        var a: A? = A()
    }
    
    let b: B? = B()
    print(b?.a?.n)
    
    /*
     but the following won't compile as compiler
     will not implicitly unwrap optionals
    
     print(b.a.n)
     */
    
  • 使用!

    class A {
        var n: Int! = 1
    }
    
    class B {
        var a: A! = A()
    }
    
    let b: B! = B()
    print(b.a.n) //compiler will implicitly unwrap `!` similar to print(b!.a!.n)
    
    //also... you can still safely unwrap if you want
    print(b?.a?.n)
    
    • b.a.nb?.a?.n都将在末尾给出Optional<Int>
    • 当然,如果banil,则b.a.n将会崩溃,因为它隐式解开了ba以到达{{ 1}}即n
    • 要获取Optional<Int>而不是Int,您可以执行Optional<Int>,因此您可以:b.a.n!获取print(residenceId!)

我希望我有道理