美文网首页
<iOS 实践>一种实体转字典的思路

<iOS 实践>一种实体转字典的思路

作者: 貘鸣 | 来源:发表于2018-06-17 09:41 被阅读38次

    在日常开发活动中, 很多时候都需要将某个实体转换为字典, 而转换字典的方式有千千万万种, 这里介绍一种利用 Swift 的反射获取属性并转换的方式.

    原理就是利用 Mirror 类提供的能力将实体中所有属性都遍历出来, 然后将属性名作为 key, 属性值作为 value 存入到字典中.

    首先定义一个协议, 有了协议之后可以很方便地为协议提供默认实现, 从而避免对每个实体类型都单独写转换方法:

    /// 字典转换协议
    protocol DictionaryConvertible {
        /// 将实体转换为字典.
        ///
        /// - Returns: 实体对应的字典
        func toDictionary() -> [String: Any]
    }
    

    定义好了这个协议, 就可以给这个协议提供默认实现了:

    extension DictionaryConvertible {
        func toDictionary() -> [String: Any] {
            var dictionary = [String: Any]()
            let mirrorSelf = Mirror(reflecting: self)
            mirrorSelf.children.forEach({ label, value in
                guard let key = label else { return }
                if let array = value as? Array<DictionaryConvertible> {
                    dictionary[key] = array.map({ $0.toDictionary() })
                } else if let convertible = value as? DictionaryConvertible {
                    dictionary[key] = convertible.toDictionary()
                } else {
                    dictionary[key] = value
                }
            })
            return dictionary
        }
    }
    

    其中考虑了实体属性是如下两种类型的可能:

    • 属性是 DictionaryConvertible, 则对该属性的值也进行字典转换.

    • 属性是 DictionaryConvertible 数组, 则将数组的每个元素都转换为字典.

    完整代码如下:

    protocol DictionaryConvertible {
        /// 将实体转换为字典.
        ///
        /// - Returns: 实体对应的字典
        func toDictionary() -> [String: Any]
    }
    
    extension DictionaryConvertible {
        func toDictionary() -> [String: Any] {
            var dictionary = [String: Any]()
            let mirrorSelf = Mirror(reflecting: self)
            mirrorSelf.children.forEach({ label, value in
                guard let key = label else { return }
                if let array = value as? Array<DictionaryConvertible> {
                    dictionary[key] = array.map({ $0.toDictionary() })
                } else if let convertible = value as? DictionaryConvertible {
                    dictionary[key] = convertible.toDictionary()
                } else {
                    dictionary[key] = value
                }
            })
            return dictionary
        }
    }
    

    在实际使用时, 假设有如下实体类型:

    struct MyInnerConsParam: Encodable, DictionaryConvertible {
        let info: String
        let price: Double
    }
    
    struct MyConsPostParam: Encodable, DictionaryConvertible {
        let name: String
        let num: Int
        let inner: MyInnerConsParam
    }
    

    只要让实体遵守 DictionaryConvertible 协议即可获取字典转换能力:

    let inner = MyInnerConsParam(info: "这个有信息", price: 33.3)
    let param = MyConPostParam(name: "二狗", num: 11, inner: inner)
    let dict = param.toDictionary()
    print(dict)
    

    打印结果如下:

    ["inner": ["info": "这个有信息", "price": 33.3], "name": "二狗", "num": 11]
    

    相关文章

      网友评论

          本文标题:<iOS 实践>一种实体转字典的思路

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