How to access deeply nested dictionaries in Swift

后端 未结 10 901
名媛妹妹
名媛妹妹 2020-11-28 04:46

I have a pretty complex data structure in my app, which I need to manipulate. I am trying to keep track of how many types of bugs a player has in thier garden. There are te

10条回答
  •  粉色の甜心
    2020-11-28 04:58

    Yet another approach using various overloaded Dictionary subscript implementations:

    let dict = makeDictionary(fromJSONString:
            """
            {
                "control": {
                    "type": "Button",
                    "name": "Save",
                    "ui": {
                        "scale": 0.5,
                        "padding": {
                            "top": 24,
                            "bottom": 32
                        }
                    }
                }
            }
            """)!
    
    dict[Int.self, ["control", "ui", "padding", "top"]] // 1
    dict[Int.self, "control", "ui", "padding", "top"]   // 2
    dict[Int.self, "control.ui.padding.top"]        // 3
    

    And the actual implementations:

    extension Dictionary {
        // 1    
        subscript(_ type: T.Type, _ pathKeys: [Key]) -> T? {
            precondition(pathKeys.count > 0)
    
            if pathKeys.count == 1 {
                return self[pathKeys[0]] as? T
            }
    
        // Drill down to the innermost dictionary accessible through next-to-last key
            var dict: [Key: Value]? = self
            for currentKey in pathKeys.dropLast() {
                dict = dict?[currentKey] as? [Key: Value]
                if dict == nil {
                    return nil
                }
            }
    
            return dict?[pathKeys.last!] as? T
        }
    
        // 2. Calls 1
        subscript(_ type: T.Type, _ pathKeys: Key...) -> T? {
            return self[type, pathKeys]
        }
    }
    
    extension Dictionary where Key == String {
        // 3. Calls 1
        subscript(_ type: T.Type, _ keyPath: String) -> T? {
            return self[type, keyPath.components(separatedBy: ".")]
        }
    }
    
    func makeDictionary(fromJSONString jsonString: String) -> [String: Any]? {
        guard let data = jsonString.data(using: .utf8)
            else { return nil}
        let ret = try? JSONSerialization.jsonObject(with: data, options: [])
        return ret as? [String: Any]
    }
    

提交回复
热议问题