9

I have a class where I have a property like this:

var residenceId: Int!

When building with Xcode 10 and Swift 4.2 there are no issues. However, after installing Xcode 11 Beta and converting to Swift 5 I get the following warning:

Implicitly unwrapped property 'residenceId' declared here

Later in the class I also have this function:

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

Here I get the warning

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

Are we no longer allowed to use implicitly unwrapped optional?

enter image description here

EDIT:

After some more looking into it, I have come to believe that "Implicitly unwrapped property 'residenceId' declared here" is not actually a warning, but rather some info (it is in a grey label rather than usual yellow) to help me understand why I am getting the second warning.

And to clarify, my question is if we are no longer able to use the '!' symbol on properties to define an implicitly unwrapped property (obviously only if we are sure it will not be nil) in order to later avoid explicitly unwrapping it (and thus simplifying the code).

Ratan Uday Kumar
  • 5,738
  • 6
  • 35
  • 54
pajevic
  • 4,607
  • 4
  • 39
  • 73
  • The second warning can be fixed using `residenceId!` or `residenceId as Int`. The first warning seems wrong to me. Note that the behavior of IUO changed in Swift 5. Now they behave like real optionals. – Sulthan Sep 09 '19 at 10:12
  • @Sulthan the op question is why this needed when var is created with `Int!` – Shehata Gamal Sep 09 '19 at 10:13
  • @Sh_Khan I am not sure if that is a question. If that's really the question, there is a ton of duplicates. – Sulthan Sep 09 '19 at 10:13
  • 2
    This article is related [Reimplementation of Implicitly Unwrapped Optionals](https://swift.org/blog/iuo/) – Joakim Danielson Sep 09 '19 at 10:15
  • I have updated my question to clarify some things. – pajevic Sep 09 '19 at 10:20
  • @Joakim Danielson I have actually read the blog post, but to be honest I am still not sure how we should treat implicitly unwrapped properties afterwards. Am I correct to assume it is no longer possible to avoid explicit unwrapping? In that case defining a property as implicitly unwrapped no longer does anything for the programmer, only for the compiler. Is this correct? – pajevic Sep 09 '19 at 10:23
  • @pajevic Attach a screenshot of the warning – staticVoidMan Sep 09 '19 at 10:29
  • @pajevic Seems only the warning text has changed but otherwise issue is the same. Will write up an answer as per my understanding – staticVoidMan Sep 09 '19 at 10:47

1 Answers1

8

Since Swift 4, ImplicitlyUnwrappedOptional or ! as we knew it, became Optional.

Check:

let a: ImplicitlyUnwrappedOptional<Int> = 1

will spit out the error:

'ImplicitlyUnwrappedOptional' has been renamed to 'Optional'

So instead if we do:

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

It's still Optional<Int> but indicates to the compiler that it can be implicitly unwrapped.

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


Now getting to the main question:

If you do:

let a: Int! = 1

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

It will give the following warning:

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

or as per Xcode 11

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

Note here that we tried to get a non-optional Any out of an Int? which means we were basically expecting an Int but just by specifying Any it won't also unwrap the Optional.
It will remain an Optional, and this is the meaning behind that warning.


Solutions:

To handle this warning gracefully, we can do any of the following:

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

EDIT: (based on comment)

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

! tells the compiler that it can be implicitly unwrapped so it can help ease in the need for optional chaining.

Example:

  • With ?

    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)
     */
    
  • With !

    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.n and b?.a?.n will both give an Optional<Int> at the end
    • Ofcourse if b or a is nil then b.a.n will crash because it's implicitly unwrapping b and a to get to n which is Optional<Int>
    • To get Int instead of Optional<Int>, you would do b.a.n! and so in your case you would do: print(residenceId!) to get Int

I hope I made sense

staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
  • It does make sense, thank you. So there is no longer a way of avoiding explicit unwrapping or providing a default value when using an implicitly unwrapped property, say if I wanna go `print("residenceId: \(residenceId)")` in my example? If so, does using `!` in stead of `?` have any practical difference for the programmer? (I know it does for the internal compiler mechanics) – pajevic Sep 09 '19 at 12:01
  • @pajevic As per the reference link using `!` `adds a flag on the declaration letting the compiler know that the declared value can be implicitly unwrapped.` So practically it will be different from `?` in the sense that it can be used without optional chaining. I will update my answer as it may be a bit misleading. Sorry 'bout that. – staticVoidMan Sep 09 '19 at 12:59
  • @pajevic Updated answer. Hope it makes things clearer :) – staticVoidMan Sep 09 '19 at 14:11
  • That was the money shot, thanks for the clarification. – pajevic Sep 09 '19 at 14:13
  • @pajevic My pleasure :) – staticVoidMan Sep 10 '19 at 06:08