How to serialize or convert Swift objects to JSON?

后端 未结 9 1697
灰色年华
灰色年华 2020-11-28 03:33

This below class

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

Needs to be converted to

相关标签:
9条回答
  • 2020-11-28 03:48

    2020 | SWIFT 5.1:

    (also works with SWIFT 4)


    Ready to work solution!

    Usage:

    var msgTemplates = [msgTemlate]()
    
    // load from file
    msgTemplates = try! Serializer.load(from: url)!
    
    // save to file
    Serializer.save(data: msgTemplates, to: url)
    

    The following code resolve 3 things:

    • 1 string to save file
    • 1 string to load file
    • ability to get/print JSON of some Codable element with 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: and ofc data must be Codable:

    struct msgTemlate: Codable { 
         //some params
    }
    

    PS2: in case of msgTemlate have enums, they are also must be Codable

    0 讨论(0)
  • 2020-11-28 03:52

    This is not a perfect/automatic solution but I believe this is the idiomatic and native way to do such. This way you don't need any libraries or such.

    Create an protocol such as:

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

    Then implement it in your class such as:

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

    Now:

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

    Note: if you want json as a string, it is very simply to convert to a string: String(data: json, encoding .utf8)

    0 讨论(0)
  • 2020-11-28 03:52

    Some of the above answers are completely fine, but I added an extension here, just to make it much more readable and usable.

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

    //This will print like the following:

    {
      "id" : 1,
      "name" : "name"
    }
    
    0 讨论(0)
  • 2020-11-28 03:53
    struct User:Codable{
     var id:String?
     var name:String?
     init(_ id:String,_ name:String){
       self.id  = id
       self.name = name
     }
    }
    

    Now just make your object like this

    let user = User("1","pawan")

    do{
          let userJson =  try JSONEncoder().encode(parentMessage) 
                
        }catch{
             fatalError("Unable To Convert in Json")      
        }
    

    Then reconvert from json to Object

    let jsonDecoder = JSONDecoder()
    do{
       let convertedUser = try jsonDecoder.decode(User.self, from: userJson.data(using: .utf8)!)
     }catch{
       
     }
    
    0 讨论(0)
  • 2020-11-28 03:55

    In Swift 4, you can inherit from the Codable type.

    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)
    
    0 讨论(0)
  • 2020-11-28 03:55

    I worked a bit on a smaller solution that doesn't require inheritance. But it hasn't been tested much. It's pretty ugly atm.

    https://github.com/peheje/JsonSerializerSwift

    You can pass it into a playground to test it. E.g. following class structure:

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

    prints

    {"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"]}}
    
    0 讨论(0)
提交回复
热议问题