Given a struct A
, I want to populate a NSDictionary
with values from that struct, provided they are not nil.
To do that I insert all the valu
As @vacawama says, you should generally steer clear of Dictionary
types with optional values, as the Dictionary
API is built around using nil
to indicate the lack of a value for a given key. Therefore using an optional type for a Dictionary
's Value
results in confusing double-wrapped optionals, which can often exhibit unintuitive behaviour.
Another (more overkill) solution would be to directly utilise dictionary literals by defining your own 'value unwrapping' ExpressibleByDictionaryLiteral
type.
extension Dictionary {
/// A dictionary wrapper that unwraps optional values in the dictionary literal
/// that it's created with.
struct ValueUnwrappingLiteral : ExpressibleByDictionaryLiteral {
typealias WrappedValue = Dictionary.Value
fileprivate let base: [Key : WrappedValue]
init(dictionaryLiteral elements: (Key, WrappedValue?)...) {
var base = [Key : WrappedValue]()
// iterate through the literal's elements, unwrapping the values,
// and updating the base dictionary with them.
for case let (key, value?) in elements {
if base.updateValue(value, forKey: key) != nil {
// duplicate keys are not permitted.
fatalError("Dictionary literal may not contain duplicate keys")
}
}
self.base = base
}
}
init(unwrappingValues literal: ValueUnwrappingLiteral) {
self = literal.base // simply get the base of the unwrapping literal.
}
}
You can then simply pass instances of this type to our init(unwrappingValues:)
initialiser:
struct A {
var first: String?
var second: String?
var third: String?
}
let a = A(first: "foo", second: nil, third: "baz")
let dictionary = Dictionary(unwrappingValues: [
"first" : a.first,
"second" : a.second,
"third" : a.third
])
print(dictionary) // ["third": "baz", "first": "foo"]