After migrating the project to swift 5, I'm getting a lot of errors such as
Expression implicitly coerced from 'UIButton?' to 'Any'
I'm not sure what's causing this. One example where this is happening(there are a bunch) is when I'm setting the view.accessibilityElements. The array is supposed to contain : [Any]?... Any idea what's causing this?
Here is an example:
@IBOutlet weak var shareButton: UIButton!
@IBOutlet weak var shareTitleLabel: UILabel!
view.accessibilityElements = [shareButton, shareTitleLabel]
Here is another example:
@IBOutlet weak var titleLabel: UILabel!
let titleConstraints = [
NSLayoutConstraint(item: titleLabel, attribute: .leading, relatedBy: .equal, toItem: otherView, attribute: .leading, multiplier: 1, constant: horizontalTextInset),
NSLayoutConstraint(item: titleLabel, attribute: .trailing, relatedBy: .equal, toItem: otherView, attribute: .trailing, multiplier: 1, constant: -horizontalTextInset)
]
When setting the elements above like this, it causes the mentioned error
A couple of observations:
It’s actually not the migration, itself, that is causing the issue. The issue is simply that you’re now compiling it Swift 5, which now warns you about the ambiguous coercion.
Since you didn’t share the precise code that produced this warning, consider this example that produces that warning:
class ViewController: UIViewController {
@IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let foo: Any = button
print(type(of: foo))
// do something with `foo`
}
}
So, glancing at this code, is foo
the optional or is it the unwrapped value? In Swift 5, it brings this ambiguity to our attention with this warning
warning: expression implicitly coerced from 'UIButton?' to 'Any'
And it will show you three possible auto-fixes to eliminate this ambiguity, namely either:
- use
nil
-coalescing operator, ??
;
- force unwrap it,
!
; or
- just cast it with
as Any
to explicitly say that foo
will be the optional with no unwrapping.
Bottom line, we want to be able to easily reason about our code, and the Any
type just makes this ambiguous. The compiler no longer makes assumptions as to whether you wanted the button
to be unwrapped or not and is asking us to make our intentions explicit.
For sake of comparison, consider the following two scenarios, where there is no ambiguity, and thus no warning. For example, considering the same implicitly unwrapped optional, here it knows that the implicit unwrapping should take place:
let foo: UIButton = button
Whereas here it knows that foo
will be the optional:
let foo: UIButton? = button
If you’re wondering why your implicitly unwrapped UIButton!
outlet is being treated as UIButton?
at all (rather than as an ImplicitlyUnwrappedOptional
type or just automatically force unwrapping it even though you’re using Any
type), there are interesting discussions related to that in Reimplementation of Implicitly Unwrapped Optionals and the SE-0054 Abolish ImplicitlyUnwrappedOptional type.