json 如何将 Swift 对象转换为字典

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31971256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:01:18  来源:igfitidea点击:

How to convert a Swift object to a dictionary

jsonswiftdictionaryservicealamofire

提问by JL Gradley

I'm relatively new to iOS programming. However, I would have assumed that Swift would have an automated way of converting objects to JSON and vice versa. That being said, I have found several libraries that can do this.

我对 iOS 编程比较陌生。然而,我会假设 Swift 有一种将对象转换为 JSON 的自动化方式,反之亦然。话虽如此,我已经找到了几个可以做到这一点的库。

HOWEVER...

然而...

It seems that no matter how you post data to a web service (even using something like AlamoFire), the requests must be a dictionary. All these forums show examples of how easy it is to convert the returned JSON string to objects. True. But the request needs to be manually coded. That is, go through all of the object properties and map them as a dictionary.

似乎无论您如何将数据发布到 Web 服务(甚至使用 AlamoFire 之类的东西),请求都必须是字典。所有这些论坛都展示了将返回的 JSON 字符串转换为对象是多么容易的示例。真的。但是请求需要手动编码。也就是说,遍历所有对象属性并将它们映射为字典。

So my question is this: Am I missing something? Have I got this all wrong and there's a super-easy way to either (a) send JSON (instead of a dictionary) in the REQUEST or (b) convert an object automatically to a dictionary?

所以我的问题是:我错过了什么吗?我是否把这一切都弄错了,有一种超级简单的方法可以 (a) 在 REQUEST 中发送 JSON(而不是字典)或 (b) 自动将对象转换为字典?

Again, I see how easy it is to deal with a JSON response. I'm just looking for an automatic way to convert the request object I want to post to a web service into a format that a library like AlamoFire (or whatever) requires. With other languages this is fairly trivial, so I'm hoping there's an equally easy and automated way with Swift.

我再次看到处理 JSON 响应是多么容易。我只是在寻找一种自动方法来将我想发布到 Web 服务的请求对象转换为像 AlamoFire(或其他)这样的库需要的格式。对于其他语言,这是相当简单的,所以我希望 Swift 有一种同样简单和自动化的方法。

采纳答案by Darko

Swift currently does not support advanced reflection like Java or C# so the answer is: no, there is not an equally easy and automated way with pure Swift.

Swift 目前不支持像 Java 或 C# 这样的高级反射,所以答案是:不,纯 Swift 没有同样简单和自动化的方法。

[Update] Swift 4 has meanwhile the Codableprotocol which allows serializing to/from JSON and PLIST.

[更新] Swift 4 同时具有Codable允许序列化到/从 JSON 和 PLIST的协议。

typealias Codable = Decodable & Encodable

回答by fencingCode

I must disagree with @Darko.

我必须不同意@Darko。

In Swift 2,

Swift 2 中

use protocol oriented programmingand the simple reflection offered by Mirrorclass :

使用面向协议的编程Mirror类提供的简单反射:

protocol JSONAble {}

extension JSONAble {
    func toDict() -> [String:Any] {
        var dict = [String:Any]()
        let otherSelf = Mirror(reflecting: self)
        for child in otherSelf.children {
            if let key = child.label {
                dict[key] = child.value
            }
        }
        return dict
    }
}

then you can use this protocol with your request class and produce the desired dictionary :

然后您可以将此协议与您的请求类一起使用并生成所需的字典:

class JsonRequest : JSONAble {
    var param1 : String?
    // ...
}

let request = JsonRequest()
// set params of the request
let dict = request.toDict()
// use your dict

回答by Michael Eilers Smith

Without using reflection, and works for nested objects (Swift 4):

不使用反射,适用于嵌套对象(Swift 4):

protocol Serializable {
    var properties:Array<String> { get }
    func valueForKey(key: String) -> Any?
    func toDictionary() -> [String:Any]
}

extension Serializable {
    func toDictionary() -> [String:Any] {
        var dict:[String:Any] = [:]

        for prop in self.properties {
            if let val = self.valueForKey(key: prop) as? String {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Int {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Double {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Array<String> {
                dict[prop] = val
            } else if let val = self.valueForKey(key: prop) as? Serializable {
                dict[prop] = val.toDictionary()
            } else if let val = self.valueForKey(key: prop) as? Array<Serializable> {
                var arr = Array<[String:Any]>()

                for item in (val as Array<Serializable>) {
                    arr.append(item.toDictionary())
                }

                dict[prop] = arr
            }
        }

        return dict
    }
}

Just implement properties and valueForKey for the custom objects you want to convert. For example:

只需为要转换的自定义对象实现属性和 valueForKey。例如:

class Question {
    let title:String
    let answer:Int

    init(title:String, answer:Int) {
        self.title = title
        self.answer = answer
    }
}
extension Question : Serializable {
    var properties: Array<String> {
        return ["title", "answer"]
    }

    func valueForKey(key: String) -> Any? {
        switch key {
        case "title":
            return title
        case "answer":
            return answer
        default:
            return nil
        }
    }
} 

You can add more value types in the toDictionary function if you need.

如果需要,您可以在 toDictionary 函数中添加更多值类型。

回答by Micha? Ziobro

My solution to this will be something like this:

我对此的解决方案将是这样的:

extension Encodable {

    var dict : [String: Any]? {
        guard let data = try? JSONEncoder().encode(self) else { return nil }
        guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] else { return nil }
        return json
    }
}

and usage will be something like this:

和用法将是这样的:

movies.compactMap { ##代码##.dict }

回答by Remy Cilia

You can also use the ObjectMapperlibrary. It has a "toJSON" method that converts your object to a dictionary.

您还可以使用ObjectMapper库。它有一个“toJSON”方法可以将您的对象转换为字典。