Reputation: 8991
If I have a dictionary with the type Dictionary<String, MyEnum>
, I cannot figure out how to convert it to an NSDictionary so I can serialiaze it to JSON via NSJSONSerialize.dataWithJSONObject
.
The compiler tells me that "Dictionary<String, MyEnum> is not convertible to NSDictionary
". Do I need to create a new dictionary with the string values of the enum a la
var newDict = Dictionary<String, String> (or <String, AnyObject>);
for (key, val) in oldDict {
newDict[key] = val;
}
or is there a better way?
Upvotes: 3
Views: 5424
Reputation: 494
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
static var allValues: [Self] { get }
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
public static var allValues: [Self] {
return Array(self.cases())
}
}
public enum ScreenName: String, EnumCollection
{
case HomeView = "Home View"
case SignUpViewController = "Domain Validate View"
var name: String {
get { return String(describing: self) }
}
var description: String {
get { return String (self.rawValue) }
}
// a dictionary mapping the raw values to the values
static var allValuesDictionary: [String : String]{
var values = [String : String]()
let mirror = Mirror(reflecting: ScreenName.allValues)
for (_, v) in mirror.children{
guard let screenName = v as? ScreenName else{continue}
values[screenName.name] = screenName.description
}
return values
}
}
Now you can call the method allValuesDictionary
will return the dictionary with <key, value> = <case, rawValue>
<HomeView, "Home View">, <SignUpViewController, "Domain Validate View">
Upvotes: 0
Reputation: 41226
NSJSONSerialize
and friends can only deal with small subset of NSObject children (NSNumber, NSString, NSArray, NSDictionary, and NSNull) that correspond to the JSON native data types. In addition, a Dictionary can only be converted to an NSDictionary if both the key and value are NSObject or inherently convertible to NSObject (String and numeric types).
In order to serialize your Dictionary you'll need to convert the Enum to one of those NSJSONSerialize data-types, similar to your example:
enum MyEnum : String {
case one = "one"
case two = "two"
}
let dict = ["one":MyEnum.one, "two":MyEnum.two]
var newDict = Dictionary<String, String>()
for (key, val) in dict {
newDict[key] = val.rawValue
}
let data = NSJSONSerialization.dataWithJSONObject(newDict, options: .allZeros, error: nil)
As an alternative, since this kind of manipulation is fairly common, you might want to consider adding this category to Dictionary, which gives it a convenient map
function:
extension Dictionary {
init(_ pairs: [Element]) {
self.init()
for (k, v) in pairs {
self[k] = v
}
}
func map<K: Hashable, V>(transform: Element -> (K, V)) -> [K: V] {
return Dictionary<K, V>(Swift.map(self, transform))
}
}
Once that's done, the conversion is simply:
let mapped = dict.map { (key, value) in (key, value.rawValue) }
Upvotes: 6