How to Add Nil Value to Swift Dictionary

How to add nil value to Swift Dictionary?

How to add nil value to Swift Dictionary?

Basically the same way you add any other value to a dictionary. You first need a dictionary which has a value type that can hold your value. The type AnyObject cannot have a value nil. So a dictionary of type [String : AnyObject] cannot have a value nil.

If you had a dictionary with a value type that was an optional type, like [String : AnyObject?], then it can hold nil values. For example,

let x : [String : AnyObject?] = ["foo" : nil]

If you want to use the subscript syntax to assign an element, it is a little tricky. Note that a subscript of type [K:V] has type V?. The optional is for, when you get it out, indicating whether there is an entry for that key or not, and if so, the value; and when you put it in, it allows you to either set a value or remove the entry (by assigning nil).

That means for our dictionary of type [String : AnyObject?], the subscript has type AnyObject??. Again, when you put a value into the subscript, the "outer" optional allows you to set a value or remove the entry. If we simply wrote

x["foo"] = nil

the compiler infers that to be nil of type AnyObject??, the outer optional, which would mean remove the entry for key "foo".

In order to set the value for key "foo" to the AnyObject? value nil, we need to pass in a non-nil outer optional, containing an inner optional (of type AnyObject?) of value nil. In order to do this, we can do

let v : AnyObject? = nil
x["foo"] = v

or

x["foo"] = nil as AnyObject?

Anything that indicates that we have a nil of AnyObject?, and not AnyObject??.

Swift - setting dictionary value to nil confusion

To remove a key in a dictionary of type [A: B], you need to set its value to an element of type B? of value nil

For instance:

var d = ["foo": 1] as [String: Int]
let v: Int? = nil
d["foo"] = v // d is now [:]

or simply

d["foo"] = nil // here nil is casted to Int?

So if we now have

var d = ["foo": nil] as [String: Any?]

A = String and B=Any?

to remove the key/value associated to foo, we need to set the value to a type B? = Any?? of value nil:

let v: Any?? = nil
d["foo"] = v // d is now [:]

What happens when we do

d["foo"] = nil

is that here nil is casted to Any?? and not Any?, so its actually different from doing

let v: Any? = nil
d["foo"] = v // d is still ["foo": nil]

and that's why the results are different.

Thanks @sliwinski for opening the discussion with apple that linked us to https://developer.apple.com/swift/blog/?id=12

How do I set a Swift dictionary nil value such that my server receives null for the key?

You should use NSNull instead of nil.

Example:

parameters["foo"] = NSNull()

Dictionary value returning nil in Swift

You should use dayDictionary[word.description.lowercased()] instead of dayDictionary[String(word)]

I tried with Playground and I added some print lines to for loop ->

for word in components {
print("word is: \(word)")
print("components is: \(components)")
print("previous is: \(previous)")
print("dayDictionary is: \(dayDictionary)")
print("item in dayDict is: \(dayDictionary[word.description.lowercased()])")

if previous == "to" {
print("Hi end")
endIndex = dayDictionary[String(word)] ?? -1
break
}

if word == "to" {
print("Hi Start")

startIndex = dayDictionary[previous] ?? -1
continue
}

if let validIndex = dayDictionary[word.description.lowercased()] {
duration += [validIndex]
print("Valid")
}

previous = String(word)
print("---------------------------------------")
}

Then the output is:

1st iteration

word is: Set
components is: ["Set", "alarm", "Monday", "to", "Friday"]
previous is:
dayDictionary is: ["tuesday": 1, "wednesday": 2, "saturday": 5, "monday": 0, "thursday": 3, "sunday": 6, "friday": 4]
item in dayDict is: nil
---------------------------------------

2nd iteration

word is: alarm
components is: ["Set", "alarm", "Monday", "to", "Friday"]
previous is: Set
dayDictionary is: ["tuesday": 1, "wednesday": 2, "saturday": 5, "monday": 0, "thursday": 3, "sunday": 6, "friday": 4]
item in dayDict is: nil
---------------------------------------

3rd iteration

word is: Monday
components is: ["Set", "alarm", "Monday", "to", "Friday"]
previous is: alarm
dayDictionary is: ["tuesday": 1, "wednesday": 2, "saturday": 5, "monday": 0, "thursday": 3, "sunday": 6, "friday": 4]
item in dayDict is: Optional(0)
Valid
---------------------------------------

4th iteration

word is: to
components is: ["Set", "alarm", "Monday", "to", "Friday"]
previous is: Monday
dayDictionary is: ["tuesday": 1, "wednesday": 2, "saturday": 5, "monday": 0, "thursday": 3, "sunday": 6, "friday": 4]
item in dayDict is: nil
Hi Start

5th iteration

word is: Friday
components is: ["Set", "alarm", "Monday", "to", "Friday"]
previous is: Monday
dayDictionary is: ["tuesday": 1, "wednesday": 2, "saturday": 5, "monday": 0, "thursday": 3, "sunday": 6, "friday": 4]
item in dayDict is: Optional(4)
Valid
---------------------------------------

Please look at the third and fifth iterations. We could get the item from dayDictionary.

Swift iOS -Get dictionary to accept nil value

Use if let to ignore nil values while adding/updating the values in the dictionary.

if let clrThree = colorClass.colorThree {
myDict.updateValue(clrThree, forKey: "thirdKey")
}

if let clrFour = colorClass.colorFour {
myDict.updateValue(clrFour, forKey: "fourthKey")
}

Reason of Crashes is,
you are using ! after the colorClass.colorFour i.e. you are using as colorClass.colorFour!.

When swift finds the value of the variable as nil and try to
forcefully unwrap it the application will crash unexpectedly found
nil while unwrapping

Check for nil in dictionary

The way of unwrapping objects of type Any that contain optionals is kind of weird but you can check that the values aren't nil in your mirror like this:

for x in Mirror(reflecting: cl).children {    
if case Optional<Any>.some(let val) = x.value {
print(type(of: val))
colorDict[x.label!] = val
}
}

Elegantly populate dictionary from a struct checking nil values

It's usually not a good idea to have a dictionary with a value that is optional. Dictionaries use the assignment of nil as an indication that you want to delete a key/value pair from the dictionary. Also, dictionary lookups return an optional value, so if your value is optional you will end up with a double optional that needs to be unwrapped twice.

You can use the fact that assigning nil deletes a dictionary entry to build up a [String : String] dictionary by just assigning the values. The ones that are nil will not go into the dictionary so you won't have to remove them:

struct A {
var first: String?
var second: String?
var third: String?
}

let a = A(first: "one", second: nil, third: "three")

let pairs: [(String, String?)] = [
("first", a.first),
("second", a.second),
("third", a.third)
]

var dictionary = [String : String]()

for (key, value) in pairs {
dictionary[key] = value
}

print(dictionary)
["third": "three", "first": "one"]

As @Hamish noted in the comments, you can use a DictionaryLiteral (which internally is just an array of tuples) for pairs which allows you to use the cleaner dictionary syntax:

let pairs: DictionaryLiteral<String,String?> = [
"first": a.first,
"second": a.second,
"third": a.third
]

All of the other code remains the same.

Note: You can just write DictionaryLiteral and let the compiler infer the types, but I have seen Swift fail to compile or compile very slowly for large dictionary literals. That is why I have shown the use of explicit types here.


Alternatively, you can skip the Array or DictionaryLiteral of pairs and just assign the values directly:

struct A {
var first: String?
var second: String?
var third: String?
}

let a = A(first: "one", second: nil, third: "three")

var dictionary = [String : String]()

dictionary["first"] = a.first
dictionary["second"] = a.second
dictionary["third"] = a.third

print(dictionary)
["third": "three", "first": "one"]


Related Topics



Leave a reply



Submit