You've gotten yourself into kind a mess, because a dictionary whose values can be nil
presents you with the prospect of a double-wrapped Optional, and therefore two kinds of nil
. There is the nil
that you get if the key is missing, and then the nil
that you get if the key is not missing and you unwrap the fetched result. And unfortunately, you're testing in a playground, which is a poor venue for exploring the distinction.
To see what I mean, consider just the following:
var d : [String:Int?] = ["Matt":1]
let val = d["Matt"]
What is the type of val
? It's Int??
- an Int wrapped in an Optional wrapped in another Optional. That's because the value inside the dictionary was, by definition, an Int wrapped in an Optional, and then fetching the value by its key wraps that in another Optional.
So now let's go a bit further and do it this way:
var d : [String:Int?] = ["Matt":nil]
let val = d["Matt"]
What is val
? Well, the playground may say it is nil
, but the truth is more complicated; it's nil
wrapped in another Optional. That is easiest to see if you print val
, in which case you get, not nil
, but "Optional(nil)"
.
But if we try for something where the key isn't there at all, we get a different answer:
let val2 = d["Alex"]
That really is nil
, signifying that the key is missing. And if we print val2
, we get "nil"
. The playground fails to make the distinction (it says nil
for both val
and val2
), but converting to a String (which is what print
does) shows the difference.
So part of the problem is this whole double-wrapped Optional thing, and the other part is that the Playground represents a double-wrapped Optional in a very misleading way.
MORAL 1: A dictionary whose value type is an Optional can get really tricky.
MORAL 2: Playgrounds are the work of the devil. Avoid them. Use a real app, and use logging to the console, or the variables pane of the debugger, to see what's really happening.