Dynamic JSON Decoding Swift 4

前端 未结 2 1596
半阙折子戏
半阙折子戏 2020-12-09 07:02

I\'m trying to decode the following JSON in Swift 4:

{
    \"token\":\"RdJY3RuB4BuFdq8pL36w\",
    \"permission\":\"accounts, users\",
    \"timout_in\":600,         


        
2条回答
  •  一整个雨季
    2020-12-09 07:52

    Inspired by @matt comments, here is the full sample I've gone with. I extended the KeyedDecodingContainer to decode the unknown keys and provide a parameter to filter out known CodingKeys.

    Sample JSON

    {
        "token":"RdJY3RuB4BuFdq8pL36w",
        "permission":"accounts, users",
        "timout_in":600,
        "issuer": "Some Corp",
        "display_name":"John Doe",
        "device_id":"uuid824fd3c3-0f69-4ee1-979a-e8ab25558421"
    }
    

    Swift structs

    struct AccessInfo : Decodable
    {
        let token: String
        let permission: [String]
        let timeout: Int
        let issuer: String
        let additionalData: [String: Any]
    
        private enum CodingKeys: String, CodingKey
        {
            case token
            case permission
            case timeout = "timeout_in"
            case issuer
        }
    
        public init(from decoder: Decoder) throws
        {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            token = container.decode(String.self, forKey: .token)
            permission = try container.decode(String.self, forKey: .permission).components(separatedBy: ",")
            timeout = try container.decode(Int.self, forKey: . timeout)
            issuer = container.decode(String.self, forKey: .issuer)
    
            // Additional data decoding
            let container2 = try decoder.container(keyedBy: AdditionalDataCodingKeys.self)
            self.additionalData = container2. decodeUnknownKeyValues(exclude: CodingKeys.self)
        }
    }
    
    private struct AdditionalDataCodingKeys: CodingKey
    {
        var stringValue: String
        init?(stringValue: String)
        {
            self.stringValue = stringValue
        }
    
        var intValue: Int?
        init?(intValue: Int)
        {
            return nil
        }
    }
    

    KeyedDecodingContainer Extension

    extension KeyedDecodingContainer where Key == AdditionalDataCodingKeys
    {
        func decodeUnknownKeyValues(exclude keyedBy: T.Type) -> [String: Any]
        {
            var data = [String: Any]()
    
            for key in allKeys
            {
                if keyedBy.init(stringValue: key.stringValue) == nil
                {
                    if let value = try? decode(String.self, forKey: key)
                    {
                        data[key.stringValue] = value
                    }
                    else if let value = try? decode(Bool.self, forKey: key)
                    {
                        data[key.stringValue] = value
                    }
                    else if let value = try? decode(Int.self, forKey: key)
                    {
                        data[key.stringValue] = value
                    }
                    else if let value = try? decode(Double.self, forKey: key)
                    {
                        data[key.stringValue] = value
                    }
                    else if let value = try? decode(Float.self, forKey: key)
                    {
                        data[key.stringValue] = value
                    }
                    else
                    {
                        NSLog("Key %@ type not supported", key.stringValue)
                    }
                }
            }
    
            return data
        }
    }
    

    Calling code

    let decoder = JSONDecoder()
    let accessInfo = try decoder.decode(AccessInfo.self, from: data!)
    
    print("Token: \(accessInfo.token)")
    print("Permission: \(accessInfo.permission)")
    print("Timeout: \(accessInfo.timeout)")
    print("Issuer: \(accessInfo.issuer)")
    print("Additional Data: \(accessInfo.additionalData)")
    

    Output

    Token: RdJY3RuB4BuFdq8pL36w
    Permission: ["accounts", "users"]
    Timeout: 600
    Issuer: "Some Corp"
    Additional Data: ["display_name":"John Doe", "device_id":"uuid824fd3c3-0f69-4ee1-979a-e8ab25558421"]
    

提交回复
热议问题