¿Cómo serializar o convertir objetos Swift a JSON?

Esta clase debajo

class User: NSManagedObject { @NSManaged var id: Int @NSManaged var name: String } 

Necesita ser convertido a

 { "id" : 98, "name" : "Jon Doe" } 

Traté de pasar manualmente el objeto a una función que establece las variables en un diccionario y devuelve el diccionario. Pero me gustaría una mejor manera de lograr esto.

En swift 4, puede heredar del tipo Codable .

 struct Dog: Codable { var name: String var owner: String } // Encode let dog = Dog(name: "Rex", owner: "Etgar") let jsonEncoder = JSONEncoder() let jsonData = try jsonEncoder.encode(dog) let json = String(data: jsonData, encoding: String.Encoding.utf16) // Decode let jsonDecoder = JSONDecoder() let dog = try jsonDecoder.decode(Dog.self, from: jsonData) 

EVReflexión :

  • Esto funciona como principio de reflexión. Esto requiere menos código y también es compatible con NSDictionary , NSCoding , Printable , Hashable y Equatable

Ejemplo:

  class User: EVObject { # extend EVObject method for the class var id: Int = 0 var name: String = "" var friends: [User]? = [] } # use like below let json:String = "{\"id\": 24, \"name\": \"Bob Jefferson\", \"friends\": [{\"id\": 29, \"name\": \"Jen Jackson\"}]}" let user = User(json: json) 

ObjectMapper :

  • Otra forma es mediante el uso de ObjectMapper. Esto le da más control pero también requiere mucho más código.

Ejemplo:

  class User: Mappable { # extend Mappable method for the class var id: Int? var name: String? required init?(_ map: Map) { } func mapping(map: Map) { # write mapping code name <- map["name"] id <- map["id"] } } # use like below let json:String = "{\"id\": 24, \"name\": \"Bob Jefferson\", \"friends\": [{\"id\": 29, \"name\": \"Jen Jackson\"}]}" let user = Mapper().map(json) 

Nota: para obtener soporte de biblioteca actualizado para JSON, consulte esta impresionante lista de Swift

Trabajé un poco en una solución más pequeña que no requiere herencia. Pero no ha sido probado mucho. Es un cajero bastante feo.

https://github.com/peheje/JsonSerializerSwift

Puede pasarlo a un patio de recreo para probarlo. Por ejemplo, siguiendo la estructura de clase:

 //Test nonsense data class Nutrient { var name = "VitaminD" var amountUg = 4.2 var intArray = [1, 5, 9] var stringArray = ["nutrients", "are", "important"] } class Fruit { var name: String = "Apple" var color: String? = nil var weight: Double = 2.1 var diameter: Float = 4.3 var radius: Double? = nil var isDelicious: Bool = true var isRound: Bool? = nil var nullString: String? = nil var date = NSDate() var optionalIntArray: Array = [1, 5, 3, 4, nil, 6] var doubleArray: Array = [nil, 2.2, 3.3, 4.4] var stringArray: Array = ["one", "two", "three", "four"] var optionalArray: Array = [2, 4, 1] var nutrient = Nutrient() } var fruit = Fruit() var json = JSONSerializer.toJson(fruit) print(json) 

huellas dactilares

 {"name": "Apple", "color": null, "weight": 2.1, "diameter": 4.3, "radius": null, "isDelicious": true, "isRound": null, "nullString": null, "date": "2015-06-19 22:39:20 +0000", "optionalIntArray": [1, 5, 3, 4, null, 6], "doubleArray": [null, 2.2, 3.3, 4.4], "stringArray": ["one", "two", "three", "four"], "optionalArray": [2, 4, 1], "nutrient": {"name": "VitaminD", "amountUg": 4.2, "intArray": [1, 5, 9], "stringArray": ["nutrients", "are", "important"]}} 

Junto con Swift 4 (Foundation) ahora es compatible de forma nativa en ambos sentidos, cadena JSON para un objeto, un objeto para cadena JSON. Consulte la documentación de Apple aquí JSONDecoder () y aquí JSONEncoder ()

Cadena JSON para objetar

 let jsonData = jsonString.data(using: .utf8)! let decoder = JSONDecoder() let myStruct = try! decoder.decode(myStruct.self, from: jsonData) 

Swift Object a JSONString

 let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data = try! encoder.encode(myStruct) print(String(data: data, encoding: .utf8)!) 

Puede encontrar todos los detalles y ejemplos aquí Guía definitiva de análisis JSON con Swift 4

Esta no es una solución perfecta / automática, pero creo que esta es la forma idiomática y nativa de hacerlo. De esta manera no necesita ninguna biblioteca o tal.

Crea un protocolo como:

 /// A generic protocol for creating objects which can be converted to JSON protocol JSONSerializable { private var dict: [String: Any] { get } } extension JSONSerializable { /// Converts a JSONSerializable conforming class to a JSON object. func json() rethrows -> Data { try JSONSerialization.data(withJSONObject: self.dict, options: nil) } } 

Luego impleméntalo en tu clase como:

 class User: JSONSerializable { var id: Int var name: String var dict { return ["id": self.id, "name": self.name] } } 

Ahora:

 let user = User(...) let json = user.json() 

Nota: si quiere json como una cadena, es muy simple convertirla a una cadena: String(data: json, encoding .utf8)

No estoy seguro de si existe lib / framework, pero si desea hacerlo automáticamente y desea evitar el trabajo manual 🙂 seguir con MirrorType

 class U { var id: Int var name: String init(id: Int, name: String) { self.id = id self.name = name } } extension U { func JSONDictionary() -> Dictionary { var dict = Dictionary() let mirror = reflect(self) var i: Int for i = 0 ; i < mirror.count ; i++ { let (childName, childMirror) = mirror[i] // Just an example how to check type if childMirror.valueType is String.Type { dict[childName] = childMirror.value } else if childMirror.valueType is Int.Type { // Convert to NSNumber for example dict[childName] = childMirror.value } } return dict } } 

Tómelo como un ejemplo aproximado, carece del soporte de conversión adecuado, carece de recursión, ... Es solo MirrorType demostración de MirrorType ...

PD Aquí se hace en U , pero vas a mejorar NSManagedObject y luego podrás convertir todas NSManagedObject subclases NSManagedObject . No es necesario implementar esto en todas las subclases / objetos administrados.

Este ejemplo de encoding en utf8.

 struct Person: Codable { var name: String var id: Int } // Encode let p = Person(name: "test", id: 1) let jsonEncoder = JSONEncoder() do { let jsonData = try jsonEncoder.encode(p) let jsonString = String(data: jsonData, encoding: .utf8) print("JSON String : " + jsonString!) } catch { print("error") } // Decode let jsonDecoder = JSONDecoder() let person = try jsonDecoder.decode(Person.self, from: jsonString)