Turn swift object into a JSON string

I have classes like these:

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
    }
}

And I would like to turn a Lad object into a JSON string like this:

  • UI Tests - isSelected is always returning false
  • How to program a delay in Swift 3
  • How to properly use VarArgs for localizing strings?
  • Swift 2 to 3 Migration for Swift Sequence Protocol
  • XCode 8.2.1 not showing documentation description on autocomplete
  • How to update value in Firebase with childByAutoId?
  • {
    “firstName”:”Markoff”,
    “lastName”:”Chaney”,
    “dateOfBirth”:
    {
    “year”:”1901″,
    “month”:”4″,
    “day”:”30″
    }
    }

    2 Solutions Collect From Internet About “Turn swift object into a JSON string”

    EDIT – 10/31/2017: This answer mostly applies to Swift 3 and possibly earlier versions. As of late 2017, we now have Swift 4 and you should be using the Encodable and Decodable protocols to convert data between representations including JSON and file encodings. (You can add the Codable protocol to use both encoding and decoding)

    The usual solution for working with JSON in Swift is to use dictionaries. So you could do:

    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
        ];  
      } 
    }
    

    and then serialize the dictionary-formatted data using 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
    }
    

    If you just need to do this for few classes, providing methods to turn them into dictionaries is the most readable option and won’t make your app noticeably larger.

    However, if you need to turn a lot of different classes into JSON it would be tedious to write out how to turn each class into a dictionary. So it would be useful to use some sort of reflection API in order to be able to list out the properties of an object. The most stable option seems to be EVReflection. Using EVReflection, for each class we want to turn into json we can do:

    extension SomeClass: EVReflectable { }
    
    let someObject: SomeClass = SomeClass();
    let someObjectDictionary = someObject.toDictionary();
    

    and then, just like before, we can serialize the dictionary we just obtained to JSON using JSONSerialization. We’ll just need to use object.toDictionary() instead of object.dataDictionary.

    If you don’t want to use EVReflection, you can implement reflection (the ability to see which fields an object has and iterate over them) yourself by using the Mirror class. There’s an explanation of how to use Mirror for this purpose here.

    So, having defined either a .dataDictionary computed variable or using EVReflection‘s .toDictionary() method, we can do

    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
        }
      }
    }
    

    May this GitHub code will help you.

    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