Assigning Implicitly Expanded Optional to Explicit Optional

If the function returns an implicitly expandable option, would you assign it an explicit optional?

For example, in Chris Adamson 's blog post, he first lists a function that returns an implicitly expanded one, and later he assigns the return value to the function to an explicit optional.

class func JSONObjectWithData(_ data: NSData!,
                      options opt: NSJSONReadingOptions,
                        error error: NSErrorPointer) -> AnyObject!

let jsonResponse : AnyObject? =
NSJSONSerialization.JSONObjectWithData(evilData,
    options: NSJSONReadingOptions(0),
    error: &parseError);

      

If a function returns something that cannot be nil, why make it optional?

+3


source to share


3 answers


In this particular case, the return AnyObject!

is a bug in the SDK (technically it's just the place where they used the auto-Swiftifier and haven't manually fixed it yet). JSONObjectWithData

can return completely nil

. From the docs:

Return Value: Foundation object from JSON data to data, or nil if an error occurs.



Chris saves this value from a possible crash by moving it to an explicit optional rather than an implicit one, which might actually be ni.

+3


source


You should always use this approach whenever you can change Implicit Unwrapped Optional

to the Optional Type

returned api, and also future releases of xcode will try to replace their api from Implicit Optionals type

to explicit optional

, and in beta 6 and 5 this approach started and many api were changed to use the type explicit optional

. The expert recommendation is to avoid Implicit Unwrapped Optional

it whenever possible because you will get a crash when nil

automatically unpacking. If you use optional(explicit)

, type must expand the value explicitly so that you do it by placing a condition if

, or if you are really sure that it will not be zero, you can expand it without if

(but you should always check in case nil

).



JSONObjectWithData

may return nil

because you don't know what is in evilData

, and if it cannot convert to json

, you will get the value nil

, and if you try to use jsonResponse

with implicit optional type

elsewhere in your code than your application will crash at runtime. This is why chris used explicit optional

to take care of this case and elsewhere where usage jsonResponse

would not automatically roll to zero, which could lead to crashes. If you expand the code yourself with if

or optional binding

, you can avoid the crash and show some meaning of the complete message.

0


source


An implicitly expanded optional parameter is still optional, although it is guaranteed to hold the value.

Assigning an implicitly expanded optional to a normal optional value is legal.

So, if you have linear logic in your application where you declare an optional variable and then initialize it with the optional unwrapped implicitly, it would be better to use the optional.

But there are cases where you define an optional variable (say at the beginning of a function) and then based on conditions, flow, etc. it can be assigned a value from different functions - if at least one of them can return a normal complementary, then you must declare the variable as optional.

But in this case, even if all the functions used to assign a value to your optional / optional variable always return either the optional, or (at least one of them) implicitly expanded optional, it is always better to stick with the optional declaration, because in the future you can create a new branch of code that returns normal optional.

Finally, very interestingly, it seems to work great :

let x: Int! = nil

      

whereas I must admit I was expecting it to throw a runtime exception . Knowing this, I think from now on, I will always use the option when the function claims to return an implicitly expanded one.

Other tests:

func test() -> Int! {
    return nil
}

let q1: Int? = test() // it works, q1 = nil (expected)
let q2: Int! = test() // it works, q2 = nil (unexpected)
let q3: Int = test() // runtime exception (expected)

      

Update : this is what, instead of documentation :

If you try to access an implicitly expanded optional if it doesn't contain a value, you will throw a runtime error. The result is exactly the same as if you put an exclamation mark after a normal optional value that does not contain a value.

This means that an assignment nil

is ok, but once it is available (i.e. assigned to another variable used in an expression, etc.) it will throw an error

-1


source







All Articles