How to Use Implicitly Unwrapped Optionals

Why create Implicitly Unwrapped Optionals , since that implies you know there's a value?

Consider the case of an object that may have nil properties while it's being constructed and configured, but is immutable and non-nil afterwards (NSImage is often treated this way, though in its case it's still useful to mutate sometimes). Implicitly unwrapped optionals would clean up its code a good deal, with relatively low loss of safety (as long as the one guarantee held, it would be safe).

(Edit) To be clear though: regular optionals are nearly always preferable.

swift - Implicit unwrapped optionals

It's all related to the class initialization.

take Outlets for example they're force unwrapped because we know they will hold a value after initialization from the XIB or Storyboard but they will not be set before the class initialization.

A force unwrapped optional exits to tell the compiler I'm taking the responsibility to make sure this variable will be set before calling it.

in your example I don't think it makes sense to write:

let aString: String! = "this is a test string"

It should just be as you wrote:

let aString: String = "this is a test string"

It makes more sense to have:

var aString: String!

meaning you'll take ownership of this variable initialization (i.e making sure it's not nil)

Why does a `nil` implicitly unwrapped optional print `nil` and not crash?

That does not crash because print accepts Any as the first parameter. Are implicitly unwrapped optionals a kind of Any? Yes they are! Anything is Any. There is no need to unwrap the optional. An implicitly unwrapped optional can be used in a place where Any is expected without unwrapping the optional.

That could potentially be confusing because now you have something with type Any, which doesn't look like it's optional, but it is an optional under the hood. To avoid this, Swift will output a warning telling you that you are implicitly coercing whatever optional type to Any.

You need to use ! to force unwrap it here:

print(x!)

How to use Implicitly Unwrapped Optionals?

As of Swift 1.0

If your deployment target is 10.10 you can use the convenience method introduced with Yosemite.

let context = NSGraphicsContext.currentContext().CGContext

If you have to support 10.9 you'll have to cast the context manually as per below.

let contextPtr = NSGraphicsContext.currentContext().graphicsPort
let context = unsafeBitCast(contextPtr, CGContext.self)

Difference between Force Unwrapping Optionals and Implicitly Unwrapped Optionals

First of all let's define an Optional

An Optional value is a container of some type (Int, String, UIColor, ...), it could contain the value (1, "Hello world", .greenColor(), ...) or nil.

let anOptionalInt: Int? = 1
let anotherOptionalInt: Int? = nil

Sample Image

When in Swift we see an Optional value we think:

Ok this could contain the actual value or nil

Force unwrapping

It's the action of extracting the value contained inside an Optional.
This operation is dangerous because you are telling the compiler: I am sure this Optional value does contain a real value, extract it!

let anOptionalInt: Int? = 1
let anInt: Int = anOptionalInt!

Now anInt contains the value 1.

Sample Image

If we perform a force unwrapping on an Optional value that happens to contain nil we get a fatalError, the app does crash and there is no way to recover it.

let anotherOptionalInt: Int? = nil
let anotherInt = anotherOptionalInt!

fatal error: unexpectedly found nil while unwrapping an Optional value

Sample Image

Implicitly unwrapped optionals

When we define an Implicitly unwrapped optional, we define a container that will automatically perform a force unwrap each time we read it.

var text: String! = "Hello"

If now we read text

let name = text

we don't get an Optional String but a plain String because text automatically unwrapped it's content.

However text is still an optional so we can put a nil value inside it

text = nil

But as soon as we read it (and it contains nil) we get a fatal error because we are unwrapping an optional containing nil

let anotherName = text

fatal error: unexpectedly found nil while unwrapping an Optional value

Alternative to implicitly unwrapped optional using @propertyWrapper in swift

You can simulate implicitly unwrapped optionals with a property wrapper as follows:

@propertyWrapper
struct MaybeUninitialized<T> {
private var storage: T?
var wrappedValue: T {
get { storage! }
set { storage = newValue}
}
}

Then you can even use possibly uninitialized fields storing optionals without accidentially unwrapping the optional. Something like this:

@MaybeUninitialized var x: Int?

print(x) // will crash
x = nil
print(x) // print nil

Implicitly unwrapped property warning?

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



Related Topics



Leave a reply



Submit