"Implicitly unwrapped property"警告?

"Implicitly unwrapped property" warning?

我有一个 class 我有一个 属性 像这样:

var residenceId: Int!

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

Implicitly unwrapped property 'residenceId' declared here

后面在class我也有这个功能:

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

这里我得到了警告

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

我们是否不再允许使用隐式解包可选?

编辑:

经过更多的研究,我开始相信 "Implicitly unwrapped property 'residenceId' declared here" 实际上并不是一个警告,而是一些信息(它是灰色标签而不是通常的黄色标签)来帮助我理解为什么我收到第二个警告。

澄清一下,我的问题是我们是否不能再使用“!”属性上的符号定义一个隐式展开的 属性(显然只有当我们确定它不会为 nil 时),以便以后避免显式展开它(从而简化代码)。

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

检查:

let a: ImplicitlyUnwrappedOptional<Int> = 1

会吐出错误:

'ImplicitlyUnwrappedOptional' has been renamed to 'Optional'

所以如果我们这样做:

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

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

Implicit Unwrapping is Part of a Declaration.

...

consider ! to be a synonym for ? with the addition that it adds a flag on the declaration letting the compiler know that the declared value can be implicitly unwrapped.
Ref: Reimplementation of Implicitly Unwrapped Optionals


现在进入主要问题:

如果你这样做:

let a: Int! = 1

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

它会给出如下警告:

Expression implicitly coerced from 'Int?' to 'Any'

或根据 Xcode 11

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

请注意,我们试图从 Int? 中得到一个非可选的 Any,这意味着我们基本上期望 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

! instead of ? have any practical difference for the programmer?

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

示例:

  • ?

    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 以到达nOptional<Int>
    • 要获得 Int 而不是 Optional<Int>,您将执行 b.a.n!,因此在您的情况下,您将执行:print(residenceId!) 以获得 Int

希望我说得有道理