“过分展开的属性”警告?

paj*_*vic 6 swift swift5

我有一堂课,我有这样的财产:

var residenceId: Int!
Run Code Online (Sandbox Code Playgroud)

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

Implicitly unwrapped property 'residenceId' declared here
Run Code Online (Sandbox Code Playgroud)

在上一节课中,我还具有以下功能:

func jsonDictionary() -> [String : Any] {
    return ["residenceId": residenceId]
}
Run Code Online (Sandbox Code Playgroud)

我在这里得到警告

Coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

编辑:

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

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

sta*_*Man 6

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

查看:

let a: ImplicitlyUnwrappedOptional<Int> = 1
Run Code Online (Sandbox Code Playgroud)

会吐出错误:

“ImplicitlyUnwrappedOptional”已重命名为“Optional”

因此,如果我们这样做:

let a: Int! = 1
print(type(of: a)) //will print "Optional<Int>"
Run Code Online (Sandbox Code Playgroud)

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

隐式解包是声明的一部分。

...

认为!是添加的同义词?,它在声明上添加一个标志,让编译器知道声明的值可以隐式解包。
Ref:隐式解包选项的重新实现


现在进入主要问题:

如果你这样做:

let a: Int! = 1

let b: Any = a
print(type(of: b)) //prints "Optional<Int>"
Run Code Online (Sandbox Code Playgroud)

它将给出以下警告:

从“Int?”隐式强制的表达式 去任何'

或根据 Xcode 11

'Int?' 类型的隐式不可包装值的强制转换 'Any' 不解包可选

请注意,我们试图Any从 an 中获取一个非可选的,Int?这意味着我们基本上期待 anInt但仅仅通过指定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
Run Code Online (Sandbox Code Playgroud)

编辑:(基于评论

!而不是对?程序员有任何实际区别?

! 告诉编译器它可以隐式解包,因此它可以帮助减轻对可选链接的需求。

例子:

  • ?

    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)
     */
    
    Run Code Online (Sandbox Code Playgroud)
  • !

    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)
    
    Run Code Online (Sandbox Code Playgroud)
    • b.a.n并且b?.a?.n都会Optional<Int>在最后给出一个
    • Ofcourse if bor ais nilthenb.a.n会崩溃,因为它隐式解包ba到达n哪个是Optional<Int>
    • 要得到Int而不是Optional<Int>,你会这样做b.a.n!,所以在你的情况下你会这样做:print(residenceId!)得到Int

我希望我说得有道理