Come serializzare o convertire oggetti Swift in JSON?

Questo sotto la class

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

Deve essere convertito a

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

Ho provato a passare manualmente l’object a una funzione che imposta le variabili in un dizionario e restituisce il dizionario. Ma vorrei un modo migliore per farlo.

In swift 4, puoi ereditare dal 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) 

EVReflection :

  • Questo funziona di principio di riflessione. Questo richiede meno codice e supporta anche NSDictionary , NSCoding , Printable , Hashable ed Equatable

Esempio:

  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 :

  • Un altro modo è usare ObjectMapper. Questo dà più controllo ma richiede anche molto più codice.

Esempio:

  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: per il supporto aggiornato delle librerie per JSON, consulta questo fantastico elenco di Swift

Ho lavorato un po ‘su una soluzione più piccola che non richiede ereditarietà. Ma non è stato testato molto. È piuttosto brutto.

https://github.com/peheje/JsonSerializerSwift

Puoi passarlo in un parco giochi per testarlo. Es. Seguente struttura di class:

 //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) 

stampe

 {"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"]}} 

Insieme a Swift 4 (Foundation) ora è supportato nativamente in entrambi i modi, stringa JSON su un object – un object su stringa JSON. Si prega di consultare la documentazione di Apple qui JSONDecoder () e qui JSONEncoder ()

JSON String to Object

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

Swift Object to JSONString

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

Puoi trovare tutti i dettagli e gli esempi qui Ultimate Guide to JSON Parsing With Swift 4

Questa non è una soluzione perfetta / automatica, ma credo che questo sia il modo idiomatico e nativo di farlo. In questo modo non hai bisogno di librerie o altro.

Crea un protocollo come:

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

Quindi implementalo nella tua class come:

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

Adesso:

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

Nota: se vuoi che json sia una stringa, è molto semplice convertire in una stringa: String(data: json, encoding .utf8)

Non sono sicuro se lib / framework esiste, ma se ti piacerebbe farlo automaticamente e vorresti evitare il lavoro manuale 🙂 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 } } 

Prendilo come esempio approssimativo, manca il corretto supporto per la conversione, manca la ricorsione, ... È solo la dimostrazione MirrorType ...

PS Qui è fatto in U , ma stai andando a migliorare NSManagedObject e poi sarai in grado di convertire tutte NSManagedObject sottoclassi NSManagedObject . Non è necessario implementarlo in tutte le sottoclassi / oggetti gestiti.

Questo esempio di codifica in 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)