27

The following code used to be able to compile in swift 2.2, no longer in swift 3.0. How do we fix this?

Error: Binary operator '===' cannot be applied to operands of type 'Any?' and 'UIBarButtonItem!'

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if sender === saveButton { // Error!
        // ... 
    } else if sender === closeButton { // Error!
        // ...
    }
}
Yuchen
  • 30,852
  • 26
  • 164
  • 234
  • Why don't you simple compare with `==`? – Evgeny Karkan Sep 17 '16 at 21:41
  • 1
    Hello @EvgenyKarkan, because I don't want to compare the value of the these two objects. But instead, I need to know whether they are the same instance. See this for more details: [Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance.](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html) – Yuchen Sep 17 '16 at 21:44

2 Answers2

49

As the error message is saying. In Swift 3, Objecitve-C id is imported as Any, and you cannot call any operations for Any including ===, without explicit cast.

Try this:

if sender as AnyObject? === saveButton {

(All the same for other sender comparison.)

And remember, in Swift 3, as AnyObject has become one of the most risky operations, you should not use as AnyObject in other cases.

OOPer
  • 47,149
  • 6
  • 107
  • 142
  • how was `id` imported prior to Swift 3? – mfaani Sep 21 '16 at 18:54
  • 1
    @Honey, Objective-C `id` was imported as `AnyObject`, and only some limited value types of Swift could be converted to `AnyObject`. – OOPer Sep 21 '16 at 18:58
  • 1
    So their major diff is: *AnyObject is only for reference types (classes), Any is for both value and reference types.* ? – mfaani Sep 21 '16 at 19:02
  • 1
    @OOPer, you mentioned in your question that "as AnyObject has become one of the most risky operations", could you explain a bit more why it is so risky? – Yuchen Nov 15 '16 at 14:37
  • 1
    @YuchenZhong, it can be a long article. First of all, you'd better read [this thread](http://stackoverflow.com/q/39033194/6541007), carefully. And consider if you want to generate a `_SwiftValue` instance, when you use `as AnyObject`. – OOPer Nov 15 '16 at 14:47
13

Try using optional binding with conditional cast to establish the type of the item before comparing:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let sender = sender as? UIBarButtonItem, sender === saveButton {
        // ...
    } else if let sender = sender as? UIBarButtonItem, sender === closeButton {
        // ...
    }
}
vacawama
  • 150,663
  • 30
  • 266
  • 294