21

I am new in Swift 4 and trying to figure out How to convert Json to swift Object automatically like Gson in java. Is there is any plugin i can use which can convert my json to object and vice versa. I have tried to use SwiftyJson Library but couldnt understand what is syntax for directly converting the json to object mapper. In Gson conversion is as follow :

String jsonInString = gson.toJson(obj);
Staff staff = gson.fromJson(jsonInString, Staff.class);

Can you please suggest some really simple example for beginner like me . below is my swift person class :

class Person  {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

below is method call to fetch response from server :

let response = Helper.makeHttpCall(url: "http://localhost:8080/HttpServices/GetBasicJson", method: "PUT", param: interestingNumbers)

In response variable I am getting json:

{
  "firstName": "John",
  "lastName": "doe"
}
nathan
  • 9,329
  • 4
  • 37
  • 51
  • 2
    Swift 4 introduces `Codable` protocol & `JSONEncoder` / `JSONDecoder` for this purpose. [Here](http://swiftjson.guide) is a really comprehensive guide on this topic. – Alladinian Jul 19 '17 at 10:51
  • Yes, seems like Codable is a solution. However, it still requires typing unlike Gson! – Markymark May 02 '20 at 05:47

2 Answers2

29

There's no need for external libraries in Swift anymore. As of Swift 4, there are 2 protocols that can achieve what you are looking for: Decodable and Encodable which are grouped into the Codable typealias, as well as JSONDecoder.

You just need to create an entity that conforms to Codable (Decodable should be enough in this example).

struct Person: Codable {
    let firstName, lastName: String
}

// Assuming makeHttpCall has a callback:
Helper.makeHttpCall(url: "http://localhost:8080/HttpServices/GetBasicJson", method: "PUT", param: interestingNumbers, callback: { response in
    // response is a String ? Data ?
    // Assuming it's Data
    let person = try! decoder.decode(Person.self, for: response)

    // Uncomment if it's a String and comment the line before
    // let jsonData = response.data(encoding: .utf8)!
    // let person = try! decoder.decode(Person.self, for: jsonData)
    print(person)
})

More info:

nathan
  • 9,329
  • 4
  • 37
  • 51
  • Right, but when is a JSONArray what do you use?! You have wrap it in a "JSONObject"? – firetrap Jan 26 '18 at 16:37
  • No. You can use `let persons = try! decoder.decode([Person.self], for: response)` – nathan Jan 26 '18 at 16:41
  • What is decoder in this instance? As Decoder is a protocol it can be instantiated. Showing your declaration for decoder would be a big help. – paul_f Apr 21 '19 at 20:41
  • 2
    @paul_f very late reply but since nobody answered and it might save a couple of minutes for others the decoder instance is actually `let decoder = JSONDecoder()`. [Source](https://developer.apple.com/documentation/foundation/jsondecoder) – grill2010 Apr 05 '21 at 11:43
2

As @nathan Suggested

"There's no need for external libraries in Swift anymore."

But If you still want to go with the third party library like ObjectMapper

class Person : Mappable {
    var firstName: String?
    var lastName: String?
    required init?(map:Map) {

    }

   func mapping(map:Map){
      //assuming the first_name and last_name is what you have got in JSON
      // e.g in android you do like @SerializedName("first_name") to map
     firstName <- map["first_name"]
     lastName <- map["last_name"]
   }

}




let person = Mapper<Person>().map(JSONObject:response.result.value)

and extending the answer by @nathan to demonstrate @SerializedName annotation equivalent in iOS using Codable

struct Person : Codable {

        let firstName : String?
        let lastName : String?

        enum CodingKeys: String, CodingKey {
                case firstName = "first_name"
                case lastName = "last_name"
        }

}
Faisal Naseer
  • 4,110
  • 1
  • 37
  • 55