swiftforced-unwrapping

Forced unwrap of a return type?


I'm starting to get my head around optionals and forced unwrapping, except for in one particular context: when it is a return type to a function.

What is the difference between:

func myFunction() -> NSData { ... }

func myFunction() -> NSData! { ... }

func myFunction() -> NSData? { ... }

Furthermore, when I use a return value of NSData!, I am forced to use ? which seems odd.

func myFunction() -> NSData! { ... }
let data = myFunction()
data?.write()

Why do I need the ? if I force unwrapped the return?


Solution

  • func myFunction() -> NSData { ... }
    

    The above means that myFunction returns an instance of NSData.


    func myFunction() -> NSData? { ... }
    

    The above means that myFunction returns a value of type Optional<NSData> (also called NSData?). Optional is an enum with two cases: .some(value) and .none (also called nil). So the function returns either an NSData (wrapped in the .some case), or nil.


    func myFunction() -> NSData! { ... }
    

    The above means that myFunction returns a value of type Optional<NSData>, just like the NSData? return type in the previous example.

    However, the use of ! means that, if you use the value of myFunction() in a way that doesn't type-check, the compiler will try unwrapping the returned value for you. So if you say this:

    let maybeLength = myFunction()?.length
    

    then the compiler will see that you are treating the return value of myFunction as an Optional<NSData>. But if you say this:

    let dataLength = myFunction().length
    

    then the compiler will see that Optional<NSData> doesn't have a length member, so it will pretend you wrote this:

    let dataLength = myFunction()!.length
    

    and if that compiles, it will carry on.

    This behavior was defined in Swift Evolution proposal SE-0054, Abolish ImplicitlyUnwrappedOptional type.


    Now let's finally consider this:

    func myFunction() -> NSData! { ... }
    let data = myFunction()
    data?.write()
    

    What is the type of data? The compiler has to infer the type of data based on the expression on the right side of the =. As I explained in the example above, the type of myFunction() is Optional<NSData>. So the type of data is Optional<NSData>, also called NSData?.

    The compiler doesn't run into any trouble making data's type NSData?, so it has no reason to implicitly unwrap the return value of myFunction.