将带有枚举值的Swift词典转换为NSDictionary

时间:2014-11-13 18:41:03

标签: ios objective-c json swift

如果我有一个类型为Dictionary<String, MyEnum>的字典,我无法弄清楚如何将其转换为NSDictionary,因此我可以通过NSJSONSerialize.dataWithJSONObject将其序列化为JSON。

编译器告诉我“Dictionary<String, MyEnum> is not convertible to NSDictionary”。我是否需要使用enum a la

的字符串值创建一个新字典
var newDict = Dictionary<String, String> (or <String, AnyObject>);
for (key, val) in oldDict {
    newDict[key] = val;
}

还是有更好的方法吗?

2 个答案:

答案 0 :(得分:5)

NSJSONSerialize和朋友只能处理对应于JSON本机数据类型的NSObject子节点(NSNumber,NSString,NSArray,NSDictionary和NSNull)的小子集。此外,如果键和值都是NSObject或者本身可以转换为NSObject(字符串和数字类型),则只能将Dictionary转换为NSDictionary。

为了序列化您的词典,您需要将Enum转换为其中一个NSJSONSerialize数据类型,类似于您的示例:

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)

作为替代方案,由于这种操作相当普遍,您可能需要考虑将此类别添加到Dictionary中,这为其提供了方便的map函数:

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))
    }
}

完成后,转换只是:

let mapped = dict.map { (key, value) in (key, value.rawValue) }

答案 1 :(得分:0)

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
    }
}

现在您可以调用方法allValuesDictionary将返回带有<key, value> = <case, rawValue>

的字典
<HomeView, "Home View">, <SignUpViewController, "Domain Validate View">