将Swift对象转换为JSON字符串

3
我有这样的类:

class MyDate
  {
    var year : String = ""
    var month : String = ""
    var day : String = ""

    init(year : String , month : String , day : String) {
        self.year = year
        self.month = month
        self.day = day
    }

}

class Lad
{
    var firstName : String = ""
    var lastName : String = ""
    var dateOfBirth : MyDate?

    init(firstname : String , lastname : String , dateofbirth : MyDate) {
        self.firstName = firstname
        self.lastName = lastname
        self.dateOfBirth = dateofbirth
    }
}

class MainCon {

    func sendData()  {


        let myDate = MyDate(year: "1901", month: "4", day: "30")
        let obj = Lad(firstname: "Markoff", lastname: "Chaney", dateofbirth: myDate)

        let api = ApiService()
        api.postDataToTheServer(led: obj)

    }

}

class ApiService {

    func postDataToTheServer(led : Lad)  {
        // here i need to json
    }
}

我希望将 Lad 对象转换为如下的JSON字符串:

{ "firstName":"Markoff", "lastName":"Chaney", "dateOfBirth": { "year":"1901", "month":"4", "day":"30" } }


注:保留HTML标记。

@vadian,你可以帮我一下吗? - Quiet Islet
你是否正在使用一些JSON框架?使用SwiftyJSON可以轻松实现你所需的功能。 - Reinier Melian
2个回答

4

编辑 - 2017年10月31日:本回答适用于Swift 3和可能的早期版本。截至2017年底,我们现在有Swift 4,您应该使用EncodableDecodable协议来在表示之间转换数据,包括JSON和文件编码。(您可以添加Codable协议来使用编码和解码)

在Swift中处理JSON的通常解决方案是使用字典。所以你可以这样做:

extension Date {
  var dataDictionary {
    return [
      "year": self.year,
      "month": self.month,
      "day": self.day
    ];
  }
}

extension Lad {
  var dataDictionary {
    return [
      "firstName": self.firstName,
      "lastName": self.lastName,
      "dateOfBirth": self.dateOfBirth.dataDictionary
    ];  
  } 
}

然后使用JSONSerialization将以字典格式排列的数据序列化。
//someLad is a Lad object

do {
  // encoding dictionary data to JSON
  let jsonData = try JSONSerialization.data(withJSONObject: someLad.dataDictionary, 
                                                   options: .prettyPrinted)

  // decoding JSON to Swift object
  let decoded = try JSONSerialization.jsonObject(with: jsonData, options: [])
  // after decoding, "decoded" is of type `Any?`, so it can't be used
  // we must check for nil and cast it to the right type        
  if let dataFromJSON = decoded as? [String: Any] {
      // use dataFromJSON
  }
} catch {
    // handle conversion errors
}

如果您只需要对少量类执行此操作,提供将它们转换为字典的方法是最易读的选项,并且不会使您的应用程序变得明显更大。
但是,如果您需要将许多不同的类转换为JSON,则编写如何将每个类转换为字典的说明会很繁琐。因此,使用某种反射API以便能够列出对象的属性将非常有用。最稳定的选择似乎是EVReflection。使用EVReflection,对于我们想要转换为json的每个类,我们可以执行以下操作:
extension SomeClass: EVReflectable { }

let someObject: SomeClass = SomeClass();
let someObjectDictionary = someObject.toDictionary();

然后,就像之前一样,我们可以使用JSONSerialization将刚刚获取的字典序列化为JSON格式。我们只需要使用object.toDictionary()而不是object.dataDictionary
如果您不想使用EVReflection,可以通过使用Mirror类来实现反射(查看对象具有哪些字段并对其进行迭代)自己。如何使用Mirror进行此目的的解释在这里
因此,无论是定义了一个.dataDictionary计算变量还是使用了EVReflection.toDictionary()方法,我们都可以执行以下操作
class ApiService {

  func postDataToTheServer(lad: Lad)  {
    //if using a custom method
    let dict = lad.dataDictionary

    //if using EVReflection
    let dict = lad.toDictionary()

    //now, we turn it into JSON
    do {
      let jsonData = try JSONSerialization.data(withJSONObject: dict, 
                                                       options: .prettyPrinted)
      // send jsonData to server
    } catch {
      // handle errors
    }
  }
}

我的回答有帮助到您吗? - Pedro Castilho
1
非常感谢您。您可以检查一下我的更新问题吗?对我的糟糕表达感到抱歉。 - Quiet Islet

-1

希望这个 GitHub 代码能对你有所帮助。

protocol SwiftJsonMappable {
   func getDictionary() -> [String: Any]
   func JSONString() -> String
}



extension SwiftJsonMappable {

//Convert the Swift dictionary to JSON String
func JSONString()  -> String {
    do {
        let jsonData = try JSONSerialization.data(withJSONObject: self.getDictionary(), options: .prettyPrinted)
        // here "jsonData" is the dictionary encoded in JSON data

        let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
        // here "decoded" is of type `Any`, decoded from JSON data
        return jsonString
        // you can now cast it with the right type

    } catch {
        print(error.localizedDescription)
    }
    return ""

}

//Convert Swift object to Swift Dictionary
func getDictionary() -> [String: Any] {
    var request : [String : Any] = [:]
    let mirror = Mirror(reflecting: self)
    for child in mirror.children {
        if let lable = child.label {
            //For Nil value found for any swift propery, that property should be skipped. if you wanna print nil on json, disable the below condition
            if !checkAnyContainsNil(object: child.value) {

                //Check whether is custom swift class
                if isCustomType(object: child.value) {
                    //Checking whether its an array of custom objects
                    if isArrayType(object: child.value) {
                        if let objects = child.value as? [AMSwiftBase] {
                            var decodeObjects : [[String:Any]] = []
                            for object in objects {
                                //If its a custom object, nested conversion of swift object to Swift Dictionary
                                decodeObjects.append(object.getDictionary())
                            }
                            request[lable] = decodeObjects

                        }
                    }else {

                        //Not an arry, and custom swift object, convert it to swift Dictionary
                        request[lable] = (child.value as! AMSwiftBase).getDictionary()
                    }
                }else {
                    request[lable] = child.value
                }
            }
        }
    }
    return request
}

//Checking the swift object is swift base type or custom Swift object
private func isCustomType(object : Any) -> Bool {

    let typeString = String(describing: type(of: object))
    if typeString.contains("String") || typeString.contains("Double") || typeString.contains("Bool") {
        return false
    }
    return true
}

//checking array
private func isArrayType(object : Any) -> Bool {

    let typeString = String(describing: type(of: object))
    if typeString.contains("Array"){
        return true
    }
    return false
}

//Checking nil object
private func checkAnyContainsNil(object : Any) -> Bool {
    let value = "\(object)"
    if value == "nil" {
        return true
    }
    return false
}

}

https://github.com/anumothuR/SwifttoJson


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接