6

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

Jay
  • 2,591
  • 1
  • 16
  • 28
  • you may take a look into this: https://stackoverflow.com/a/40455613/2231118 – bpolat Mar 29 '19 at 17:50
  • @bpolat I saw that earlier, but this hasn't happened with any previous migration. Since IBOutlets are implicitly unwrapped optionals, I shouldn't have any problems putting their references inside of an array. So I'm unsure if it's a compiler bug or what ... – Jay Mar 29 '19 at 17:57
  • ***this hasn't happened with any previous migration.*** Please show exact version of Xcode and the exact code. I can re-check some versions for you. And definitely this is not a compiler bug and you need to modify your code. – OOPer Mar 29 '19 at 22:37
  • I've added the code @OOPer – Jay Apr 01 '19 at 16:01
  • Sorry, sorry. My deleted comment was a mistake and I forgot to convert the project to use Swift 5, and you hit the edge case where only Swift 5 shows different behavior. All that said, I repeat that this is not a compiler bug. Please check [SE-0054](https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md) and [SE-0140](https://github.com/apple/swift-evolution/blob/master/proposals/0140-bridge-optional-to-nsnull.md). – OOPer Apr 01 '19 at 18:36
  • 1
    I have the same issues (migrating to swift 5 from swift 4) with XCode 10.2 – Klinki Apr 02 '19 at 09:35
  • I am having a similar project. SE-0054 says this was implemented in Swift 4.2, however I get no such warning in any of projects using Swift 4.2, it only occurs after migration to Swift 5.0. – AdamM Apr 03 '19 at 17:52

1 Answers1

10

A couple of observations:

  1. 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.

  2. 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
    
  3. 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.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 1
    I added an edit that shows 2 examples of where this is happening – Jay Apr 01 '19 at 16:09
  • 2
    What is the ideal solution to resolve this warning. Force unwrap or casting to Any do not seem like particularly clean solutions. – AdamM Apr 03 '19 at 17:53
  • 1
    In case of IBOutlet (which is implicitly unwrapped anyway), I’d personally just use the forced unwrapping operator, `!`. – Rob Apr 03 '19 at 18:46
  • Whats the point of having `UIButton!` as the type then? there doesn't seem to be a difference now between `UIButton?` and `UIButton!`. I would expect with `foo: Any = button` where the type of button is `UIButton!`, that the type of foo would be `UIButton` not the optional... – Jonathan. Sep 10 '19 at 01:53
  • What’s the point? Well, you still enjoy the implicitly unwrapping behavior where unambiguous (e.g. `button.backgroundColor = ...`). It’s only a problem with `Any`, where it is unclear. Bottom line, don’t think of `!` optionals as a “type” any more: “A mental model many people have for implicitly unwrapped optionals is that they are a type, distinct from regular optionals. ... The new mental model for IUOs is one where you 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.” – Rob Sep 10 '19 at 12:32