Coercion of implicitly unwrappable value

If you’ve been migrating code to Xcode 11 you might have seen a compiler warning about coercion of implicitly unwrappable values. It didn’t make much sense to me until I hit a practical example.

Updating to Xcode 11

I’ve been updating my Auto Layout book for Xcode 11 and iOS 13. Apart from a minor change to size classes, and some improvements to scroll view layouts with Interface Builder, most of the changes are due to changes in the Xcode 11 user interface.

I suppose it’s a sign of how mature Swift is that I’ve needed to make almost no code changes. I did come across one new compiler warning though…

Coercion of implicitly unwrappable value???

Here’s the line of code that had me scratching my head. It creates a trailing constraint between a redView and the root view of a view controller using the old and painful NSLayoutConstraint API:

 NSLayoutConstraint(item: view, attribute: .trailing,
   relatedBy: .equal, toItem: redView,
   attribute: .trailing, multiplier: 1.0,
   constant: padding),

Note: Don’t write constraints this way. This line of code is from an example showing how not to create constraints. The safer and more concise layout anchors API has long been a better choice.

Xcode 11 complains about the view passed as the first argument:

Coercion of implicitly unwrappable value of type ‘UIView?’ to ‘Any’ does not unwrap optional

The Xcode warning offers a number of fixes:

Xcode warning: Coercion of implicitly unwrappable value

The implicitly unwrappable value is the root view of a view controller. The default value for this property is nil. A view controller lazily loads its view when you first access the property. You don’t usually have to think about this as the view controller declares it as an Implicitly Unwrapped Optional (IUO):

var view: UIView!

The warning comes from the way modern Swift handles IUO’s. See SE-0054 for the details:

the appearance of ! at the end of a property or variable declaration’s type no longer indicates that the declaration has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has an attribute indicating that its value may be implicitly forced.

We can confirm this by looking at the type of an IUO:

var view: UIView!
type(of: view)    // Optional<UIView>

It’s better to think about IUO’s as optionals that gets some special handling when used:

A reference to an IUO variable or property prefers to bind to an optional, but may be implicitly forced (i.e. converted to the underlying type) when being type-checked;

When it’s safe to do so, the compiler force unwraps the optional. So I can pass view to a method that expects a non-optional view and the compiler unwraps it:

func formatView(_ view: UIView) {
  view.backgroundColor = .red
  ...
}

formatView(view)   // view is an IUO

Coming back to our Xcode warning. The problem comes from the NSLayoutConstraint initializer. The first parameter is not a UIView but of type Any:

// NSLayoutConstraint
init(item view1: Any, ...)

As the name suggests, Any can represent any type, including optional types. The compiler prefers to bind to an optional when dealing with an IUO so our optional view is not unwrapped. This might not be what we want so it’s a good idea to follow the advice from Xcode and make it explicit.

Silencing the warning

The Xcode fix-it suggests providing a default value, force unwrapping or explicitly casting to Any (using as Any). We have a better solution this time, switch to using layout anchors:

view.trailingAnchor.constraint(equalTo: redView.trailingAnchor,
  constant: padding),

Alternatively, force unwrapping is not always a bad thing. If the root view returns nil we have bigger problems:

NSLayoutConstraint(item: view!, ...

If force unwrapping makes you uneasy, you could conditionally unwrap with a guard or if let. The end result is much the same:

guard let view = view else { fatalError(...) }

This advice from the Swift blog on the Reimplementation of Implicitly Unwrapped Optionals is also worth bearing in mind:

You’ll probably be exposed to implicit unwrapping as a result of interacting with imported Objective-C APIs. You might occasionally find it convenient to use implicit unwrapping when declaring @IBOutlet properties, or in other places where you know you won’t access a value until it has been fully initialized. However, you are usually better off avoiding implicit unwrapping and should use explicit unwrapping through if let and guard let. When you’re certain it’s safe, use explicit force-unwrapping via !.

Read more