如何将Swift对象转换为字典

JL *_*ley 30 service json dictionary swift alamofire

我对iOS编程比较陌生.但是,我会假设Swift有一种将对象转换为JSON的自动方式,反之亦然.话虽这么说,我发现有几个库可以做到这一点.

然而...

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

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

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

fen*_*ode 45

我必须不同意@Darko.

Swift 2中,

使用面向协议的编程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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

let request = JsonRequest()
// set params of the request
let dict = request.toDict()
// use your dict
Run Code Online (Sandbox Code Playgroud)

  • 怎么没有证件?请参阅[Apple API](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Mirror_Structure/index.html#//apple_ref/swift/tdef/s:VSs6Mirror5Child) (2认同)
  • Apple Swift标准库参考:[`Mirror Structure Reference`](https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Mirror_Structure/index.html)...这是一个发布链接先前评论过的".../prerelease/ios/..."链接. (2认同)
  • 苹果医生说:"镜子被游乐场和调试人员使用." 那么它可以在App Store的生产代码中使用吗? (2认同)

Mic*_*bro 12

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

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
    }
}
Run Code Online (Sandbox Code Playgroud)

和用法将是这样的:

movies.compactMap { $0.dict }
Run Code Online (Sandbox Code Playgroud)


Dar*_*rko 8

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

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

typealias Codable = Decodable & Encodable
Run Code Online (Sandbox Code Playgroud)


Mic*_*ith 5

无需使用反射,并且适用于嵌套对象(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
    }
}
Run Code Online (Sandbox Code Playgroud)

只需为要转换的自定义对象实现属性和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
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

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


小智 5

经过对 Stack Overflow 的大量挖掘后,我发现的最新解决方案是:

//This block of code used to convert object models to json string
let jsonData = try JSONEncoder().encode(requestData)
let jsonString = String(data: jsonData, encoding: .utf8)!
print(jsonString)

//This method is used to convert jsonstring to dictionary [String:Any]
func jsonToDictionary(from text: String) -> [String: Any]? {
    guard let data = text.data(using: .utf8) else { return nil }
    let anyResult = try? JSONSerialization.jsonObject(with: data, options: [])
    return anyResult as? [String: Any]
}

//Use above method something like this
let params = jsonToDictionary(from: jsonString) ?? [String : Any]()
 
//Use params to pass in paramters
Alamofire.request(completeUrl, method: .post, parameters: params, encoding:JSONEncoding.prettyPrinted, headers: myHeaders){
        
        response in

       //Do whatever you want with response of it.
        
    }
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 我结合了多个答案的解决方案。
  2. 我将这个解决方案与 alamofire 一起使用,因为 alamofire 只接受这种格式的参数“[String:Any]”。