美文网首页
swift codable和mirror

swift codable和mirror

作者: flionel | 来源:发表于2018-07-23 19:58 被阅读82次

    1. Codable

    在swift 4中引入codable之后,可以将Cat声明为Codable(或者至少声明为Encodable,记住Codable其实就是Decodable & Encodable),然后使用相关的encoder来进行编码。不过swift标准库中并没有直接将一个对象编码为字典的编码器,我们可以进行一些变通,先将需要处理的类型声明为Coable,然后使用JSONEncoder将其转换为JSON数据,最后再从JSON数据中拿到对应的字典,如下代码所示,

    // public typealias Codable = Decodable & Encodable
    struct Cat: Codable {
        let name: String
        let age: Int
    }
    
    let kitten = Cat.init(name: "kitten", age: 2)
    let encoder = JSONEncoder()
    
    do {
        let data = try encoder.encode(kitten)
        let dictionary = try JSONSerialization.jsonObject(with: data, options: [])
        print(dictionary)
    } catch {
        print(error)
    }
    
    

    2. Mirror

    Mirror可以让我们在运行时一窥某个类型的实例的内容,它也是swift中位数不多的与运行时特性相关的手段。Mirror的最基本的用法如下,

    
    struct Cat {
        let name: String
        let age: Int
    }
    
    let kitten = Cat.init(name: "kitten", age: 2)
    let mirror = Mirror.init(reflecting: kitten)
    for child in mirror.children {
        print("\(child.label!) - \(child.value)")
    }
    

    通过访问实例中mirror.children的每一个child,就可以得到所有的存储属性的label和value。以label为字典键,value为字典值,我们就能从任意类型构建出对应的字典。

    字典中值的类型

    不过逐一,这个child中的值是以Any为类型的,也就是说任意类型都可以在child.value中表达。所以还需要做一些额外的类型保证的工作,这里添加一个DictionaryValue协议,来表示字典能接受的类型,如下代码所示,

    
    protocol DictionaryValue {
        var value: Any { get }
    }
    
    extension Int: DictionaryValue {
        var value: Any {
            return self
        }
    }
    
    extension Float: DictionaryValue {
        var value: Any {
            return self
        }
    }
    
    extension String: DictionaryValue {
        var value: Any {
            return self
        }
    }
    
    extension Bool: DictionaryValue {
        var value: Any {
            return self
        }
    }
    

    进一步对DictionaryValue协议进行扩展,让满足它的其他类型通过Mirror的方式来构建字典,如下代码所示,

    extension DictionaryValue {
        var value: Any {
            let mirror = Mirror(reflecting: self)
            var result = [String: Any]()
            for child in mirror.children {
                // 如果无法获得正确的key,则报错
                guard let key = child.label else {
                    fatalError("Invalid key in child:\(child)")
                }
                
                // 如果value无法转换为DictionaryValue,则报错
                if let value = child.value as? DictionaryValue {
                    result[key] = value.value
                } else {
                    fatalError("Invalid value in child: \(child)")
                }
            }
            return result
        }
    }
    
    
    struct Cat1: DictionaryValue {
        let name: String
        let age: Int
    }
    
    let kitten1 = Cat1.init(name: "kitten", age: 2)
    print(kitten1.value)
    

    对于潜逃自定义DictionaryValue值的其他类型,字段转换也可以正常工作,如下代码,

    struct Wizard: DictionaryValue {
        let name: String
        let cat: Cat1
    }
    
    let wizard = Wizard.init(name: "hermione", cat: kitten1)
    print(wizard.value)
    

    字典中的嵌套数组和字典

    extension Array: DictionaryValue where Element: DictionaryValue {
        var value: Any { return map{ $0.value } }
    }
    
    extension Dictionary: DictionaryValue where Value: DictionaryValue {
        var value: Any { return mapValues { $0.value } }
    }
    
    
    /*
    // 适配swift 4.1之前的代码
     extension Array: DictionaryValue {
     var value: Any { return map { ($0 as! DictionaryValue).value } }
     }
     extension Dictionary: DictionaryValue {
     var value: Any { return mapValues { ($0 as! DictionaryValue).value } }
     }
     */
    
    struct Gryffindor: DictionaryValue {
        let wizards: [Wizard]
    }
    
    let crooks = Cat1.init(name: "Crookshanks", age: 2)
    let hermione = Wizard.init(name: "hermione", cat: crooks)
    
    
    let hedwig = Cat1.init(name: "hedwig", age: 3)
    let harry = Wizard.init(name: "Harry", cat: hedwig)
    let gryfindor = Gryffindor.init(wizards: [harry, hermione])
    print(gryfindor.value)
    
    

    4. 参考链接

    相关文章

      网友评论

          本文标题:swift codable和mirror

          本文链接:https://www.haomeiwen.com/subject/dzzjmftx.html