3
votes
self.presentTextInputControllerWithSuggestions(nil, allowedInputMode: WKTextInputMode.Plain) { (results:[AnyObject]!) -> Void in
    // results can be nil
    if let speech = results.first as? String {
        debugPrint(speech)
    }
}

Excuse my ignorance, I'm afraid I've missed some basic understanding of optionals. I'm under the impression that !, the implictly unwrapped optional indicator, is a guarantee that the variable of that type is not nil. Yet this very straightforward Apple API will infrequently return me nil.

Is this an unintended bug or part of the spec for Optionals? Because if this is part of the spec, I don't understand why there are optionals in the first place as opposed to having variables that can either be present or nil.

3
nil and empty array is not the sameSulthan
It's because Apple hasn't finished converting all of the libraries to use the Objective-C nullability annotations yet.nhgrif

3 Answers

7
votes

I'm under the impression that !, the implictly unwrapped optional indicator, is a guarantee that the variable of that type is not nil.

That’s a mis-impression I’m afraid. Implicitly-unwrapped optionals can very much be nil. Only something that isn’t declared with any optional qualifier, neither ? nor !, is guaranteed to be non-nil.

So:

var definitelyCouldBeNilForcedToCheck: String?
var mightBeNilButProbablyNotBECAREFUL: String!
var definitelyNotEverNil: String

There are two use cases for implicitly-unwrapped optionals:

  1. When you are absolutely positively certain that your value won’t be nil, except briefly in very controlled circumstances. For example suppose you have a function that does some processing in its failable initializer. Like this:

    class FileHandler {
        let fileHandle: SomeFileHandleType!
    
        init?(fileName: String) {
            fileHandle = open(fileName)
            if fileHandle == nil { return nil }
        }
    
        deinit {
            if fileHandle != nil {
                fileHandle.close()
            }
        }
    
        func variousMethods() {
            // can just use fileHandle without bothering about
            // unwrapping it, because it cannot possibly be nil
            // based on how you’ve written your code
        }
    }
    
  2. When you have a massive corpus of Objective-C (lets say, Cocoa or UIKit), and you have no idea when some pointer is returned whether it can be nil or not. And most of the time you think it probably isn’t, and it would be really annoying to make your API users have to unwrap stuff constantly, but then again, you don’t know for certain it can’t be nil and you want them to read the documentation instead. But they’ll probably forget, but what can you do? Eventually you’ll audit all the functions and then make them optionals or non-nullable values.

1
votes

Whenever you see a method signature with an ! operator in it like this, you must check it for nil.

In most cases, the argument will be an implicitly unwrapped optional because it's from an Objective-C library which hasn't been updated to account for the Objective-C nullability annotations yet (which Objective-C source code files use to tell Swift whether or not the argument should be an optional).

Objective-C doesn't support the idea of optionals.

If this is from an Apple library, it's only a matter of time before they release an Xcode update which will address this and change the argument to either a non-optional or an optional. Apple has no long-term plans for leaving any implicitly unwrapped optionals in their parameters.

0
votes

No, This symbol ! is not a guarantee the variable is not nil.

Optionals in swift is tricky.

let's say you have the following variable of type String

var name: String?

This is not a string. It's an optional string which is a different thing.

however the following:

var name: String!

is an implicitly unwrapped optional which means calling name will always give the string not the optional string which could be nil.

Normally use implicitly unwrapped optional if you want your code to crash if the optional is nil.