2
if let mathematicalSymbol = sender.currentTitle {
    brain.performOperation(mathematicalSymbol)
}

The code above introduces the error below;

Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?

As can be seen in this screen shot;

enter image description here

sender.currentTitle is an optional.

Here is an excerpt from Apple's "The Swift Programming Language (Swift 2.2)" with its example code just below it;

If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.

Here is the sample code for that excerpt;

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}

So for these reasons, I'm thinking that either I'm missing something or that I'm hitting a bug.

I've also tried something similar on a Playground, and didn't get a similar error;

enter image description here

Here is my Swift version;

Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)
Target: x86_64-apple-macosx10.9
emreerokyar
  • 359
  • 3
  • 12
  • Possibly related: [The strange behaviour of Swift's AnyObject](http://stackoverflow.com/questions/33388830/the-strange-behaviour-of-swifts-anyobject). – Martin R Aug 01 '16 at 17:45

1 Answers1

3

If you look at currentTitle, you'll see it is likely inferred to be String??. For example, go to currentTitle in Xcode and hit the esc key to see code completion options, and you'll see what type it thinks it is:

enter image description here

I suspect you have this in a method defining sender as AnyObject, such as:

@IBAction func didTapButton(sender: AnyObject) {
    if let mathematicalSymbol = sender.currentTitle {
        brain.performOperation(mathematicalSymbol)
    }
}

But if you explicitly tell it what type sender is, you can avoid this error, namely either:

@IBAction func didTapButton(sender: UIButton) {
    if let mathematicalSymbol = sender.currentTitle {
        brain.performOperation(mathematicalSymbol)
    }
}

Or

@IBAction func didTapButton(sender: AnyObject) {
    if let button = sender as? UIButton, let mathematicalSymbol = button.currentTitle {
        brain.performOperation(mathematicalSymbol)
    }
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • `if let mathematicalSymbol = (sender as? UIButton)?.currentTitle {` also works. – vacawama Aug 01 '16 at 17:48
  • 1
    I find it annoying that Xcode defaults to `AnyObject` for the `sender` type. `AnyObject` is rarely what anyone would want for the sender, so the user should have to choose it if they really want it, IMHO. – vacawama Aug 01 '16 at 17:58
  • 2
    Agreed. When I drag-and-drop my `IBAction` connections, I always pick the specific type in the dropdown, rather than accepting the `AnyObject` default. I disliked this latter behavior in Objective-C, and it's even worse now, being so unswifty. – Rob Aug 01 '16 at 18:07
  • 1
    @Rob, you're right on point. This was the exact issue I was experiencing, upon checking the type of my `sender`, I noticed that it was `AnyObject` as you guessed. I always try to change it but forgot to do so in this occasion, hence this error. When I used `UIButton`, it was resolved. Also, checking the type of `UIButton` shows as `String?` as expected - as opposed to `String??` for `AnyObject`. Apple really should change the behaviour of defaulting to `AnyObject`. Thanks a lot! – emreerokyar Aug 02 '16 at 01:55