Dictionary<AnyHashable: Any> where Any may hold nil value in Swift 3

11.8k views Asked by At

Can someone explain why this works in Swift 3?

var dict: [AnyHashable: Any]
let b: AnyObject? = nil
let c = b as Any

dict = ["a": "aa", "b": c]

If I test

dict["b"] == nil

It returns false. Is it supposed to be right?

2

There are 2 answers

0
OOPer On BEST ANSWER

Assuming you are using the latest Xcode, 8.1 (8B62) with Swift 3.0.1 .

Any containing nil is not so easy as simple nested optional:

Nested Optional

var dictWithOptional: [String: AnyObject?] = [
    "a": "aa" as NSString,
    "b": nil,
]
if let b = dictWithOptional["b"] { //<-check if `dict` contains value for "b"
    print(b) //->nil (with compiletime warning)
    print(b == nil) //->true
}

b == nil returns true.

Any containing nil

var dict: [AnyHashable: Any]
let b: AnyObject? = nil
let c = b as Any
dict = ["a": "aa", "b": c]

print(Array(dict.keys)) //->[AnyHashable("b"), AnyHashable("a")]
if let b = dict["b"] { //<-check if `dict` contains value for "b"
    print(b) //->nil
    print(b == nil) //->false (with compiletime warning)
}

b == nil becomes false as written by the OP.

You can detect nil in Any, with something like this:

if let b = dict["b"] { //<-check if `dict` contains value for "B"
    if b as AnyObject === NSNull() {
        print("b is nil") //->b is nil
    }
}

(This works in Swift 3.0.1, not in Swift 3.0.0 .)

0
bobDevil On

You're running into nested optionals. If a dictionary holds a type E, then the dictionary access method returns a value of type E?, either the value if it exists, or nil.

In your case, you've created a dictionary where the value is an optional. So the E above is something like Any?. This means the return value of the getter is E? i.e., Any??

In your case, dict["b"] returns a non-nil optional, containing the value 'nil'

Putting your code in a playground and printing dict["b"] confirms this by printing the string Optional(nil)