To poniżej klasy
class User: NSManagedObject {
@NSManaged var id: Int
@NSManaged var name: String
}
Musi zostać przekonwertowany na
{
"id" : 98,
"name" : "Jon Doe"
}
Próbowałem ręcznie przekazać obiekt do funkcji, która ustawia zmienne w słowniku i zwraca słownik. Ale chciałbym mieć lepszy sposób, aby to osiągnąć.
Odpowiedzi:
W Swift 4 możesz dziedziczyć po
Codable
typie.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 secondDog = try jsonDecoder.decode(Dog.self, from: jsonData)
źródło
class
(czego potrzebuję), a niestruct
.Wraz ze Swift 4 (Foundation) jest teraz natywnie obsługiwany na oba sposoby, ciąg JSON do obiektu - obiekt do ciągu JSON. Zobacz dokumentację Apple tutaj JSONDecoder () i tutaj JSONEncoder ()
Ciąg JSON do obiektu
let jsonData = jsonString.data(using: .utf8)! let decoder = JSONDecoder() let myStruct = try! decoder.decode(myStruct.self, from: jsonData)
Swift Object do JSONString
let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data = try! encoder.encode(myStruct) print(String(data: data, encoding: .utf8)!)
Wszystkie szczegóły i przykłady można znaleźć tutaj. Ultimate Guide to Parsing JSON With Swift 4
źródło
AKTUALIZACJA:
Codable
protokół wprowadzony w Swift 4 powinien wystarczyć w większościJSON
przypadków analizowania. Poniższa odpowiedź jest przeznaczona dla osób, które utknęły w poprzednich wersjach Swifta iz powodów starszychEVReflection :
NSDictionary
,NSCoding
,Printable
,Hashable
iEquatable
Przykład:
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 :
Przykład:
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<User>().map(json)
źródło
Pracowałem trochę nad mniejszym rozwiązaniem, które nie wymaga dziedziczenia. Ale nie zostało to zbytnio przetestowane. To dość brzydki bankomat.
https://github.com/peheje/JsonSerializerSwift
Możesz przekazać go na plac zabaw, aby go przetestować. Np. Następująca struktura klas:
//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<Int?> = [1, 5, 3, 4, nil, 6] var doubleArray: Array<Double?> = [nil, 2.2, 3.3, 4.4] var stringArray: Array<String> = ["one", "two", "three", "four"] var optionalArray: Array<Int> = [2, 4, 1] var nutrient = Nutrient() } var fruit = Fruit() var json = JSONSerializer.toJson(fruit) print(json)
wydruki
{"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"]}}
źródło
To nie jest idealne / automatyczne rozwiązanie, ale uważam, że jest to idiomatyczny i rodzimy sposób, aby to zrobić. W ten sposób nie potrzebujesz żadnych bibliotek ani tym podobnych.
Utwórz protokół, taki jak:
/// 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) } }
Następnie zaimplementuj to w swojej klasie, na przykład:
class User: JSONSerializable { var id: Int var name: String var dict { return ["id": self.id, "name": self.name] } }
Teraz:
let user = User(...) let json = user.json()
Uwaga: jeśli chcesz
json
jako ciąg, bardzo łatwo jest przekonwertować na ciąg:String(data: json, encoding .utf8)
źródło
Niektóre z powyższych odpowiedzi są całkowicie w porządku, ale dodałem tutaj rozszerzenie, aby było bardziej czytelne i użyteczne.
extension Encodable { var convertToString: String? { let jsonEncoder = JSONEncoder() jsonEncoder.outputFormatting = .prettyPrinted do { let jsonData = try jsonEncoder.encode(self) return String(data: jsonData, encoding: .utf8) } catch { return nil } } } struct User: Codable { var id: Int var name: String } let user = User(id: 1, name: "name") print(user.convertToString!)
// To wydrukuje się w następujący sposób:
{ "id" : 1, "name" : "name" }
źródło
Nie jestem pewien, czy istnieje biblioteka / framework, ale jeśli chciałbyś to zrobić automatycznie i chciałbyś uniknąć pracy fizycznej :-) trzymaj się
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<String, Any> { var dict = Dictionary<String, Any>() 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 } }
Potraktuj to jako przybliżony przykład, brak odpowiedniej obsługi konwersji, brak rekursji, ... To tylko
MirrorType
demonstracja ...PS Tutaj jest to zrobione
U
, ale zamierzasz ulepszyćNSManagedObject
i wtedy będziesz mógł przekonwertować wszystkieNSManagedObject
podklasy. Nie ma potrzeby implementowania tego we wszystkich podklasach / obiektach zarządzanych.źródło
@NSManaged
. Może to powoduje twój problem. W tym przypadku zapisałbym to w Objective-C, a następnie użyję go z Swift.2020 | SWIFT 5.1:
(działa również z SWIFT 4)
Gotowe do pracy rozwiązanie!
Stosowanie:
var msgTemplates = [msgTemlate]() // load from file msgTemplates = try! Serializer.load(from: url)! // save to file Serializer.save(data: msgTemplates, to: url)
Poniższy kod rozwiązuje 3 rzeczy:
element.toJsonString
import Foundation public class Serializer{ static func save<T>(data: T, to url: URL) where T : Encodable{ guard let json = data.toJsonString else { return } do { try json.write(to: url, atomically: true, encoding: String.Encoding.utf8) } catch { /* error handling here */ } } static func load<T>(from url: URL) throws -> T? where T : Decodable { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 // for human-read date format guard let dataStr = try? String(contentsOf: url, encoding: String.Encoding.utf8 ), let data = dataStr.data(using: String.Encoding.utf8 ), let result = try? decoder.decode( T.self , from: data) else { return nil } return result } } extension Encodable { var toJsonString: String? { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted // nice formatted for reading by human encoder.dateEncodingStrategy = .iso8601 // for human-read date format do { let jsonData = try encoder.encode(self) return String(data: jsonData, encoding: .utf8) } catch { return nil } } }
PS: i dane ofc muszą być kodowalne:
struct msgTemlate: Codable { //some params }
PS2: w przypadku, gdy msgTemlate ma wyliczenia, muszą one również być kodowane
źródło
struct User:Codable{ var id:String? var name:String? init(_ id:String,_ name:String){ self.id = id self.name = name } }
let user = użytkownik ("1", "pawan")
do{ let userJson = try JSONEncoder().encode(parentMessage) }catch{ fatalError("Unable To Convert in Json") }
let jsonDecoder = JSONDecoder() do{ let convertedUser = try jsonDecoder.decode(User.self, from: userJson.data(using: .utf8)!) }catch{ }
źródło