如何序列化或将Swift对象转换为JSON?

Pen*_*esh 64 json swift

这下面的课程

class User: NSManagedObject {
  @NSManaged var id: Int
  @NSManaged var name: String
}
Run Code Online (Sandbox Code Playgroud)

需要转换为

{
    "id" : 98,
    "name" : "Jon Doe"
}
Run Code Online (Sandbox Code Playgroud)

我尝试手动将对象传递给一个函数,该函数将变量设置为字典并返回字典.但我想要一个更好的方法来实现这一目标.

Etg*_*gar 88

在swift 4中,您可以继承该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)
Run Code Online (Sandbox Code Playgroud)

  • 编码类型应为.utf8而不是.utf16 (14认同)
  • 我试过utf16,它把我的json变成了中文? (7认同)
  • @ChanJingHong 这取决于您要编码的内容 (3认同)
  • 问题具体是关于编码“类”(我需要的)而不是“结构”。 (3认同)

moh*_*acs 27

与Swift 4(Foundation)一起,它现在以两种方式本地支持,JSON字符串到对象 - JSON字符串的对象.请在此处查看Apple的文档JSONDecoder()和此处的JSONEncoder()

JSON String to Object

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

Swift对象到JSONString

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

你可以在这里找到所有细节和例子.使用Swift 4进行JSON解析的终极指南


Pen*_*esh 25

更新: Codable Swift 4中引入的协议应该足以满足大多数JSON解析案例.以下答案适用于陷入Swift早期版本并且由于遗留原因而被困的人

EVReflection:

  • 这是反射原理的作品.这需要更少的代码,同时还支持NSDictionary,NSCoding,Printable,HashableEquatable

例:

    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)
Run Code Online (Sandbox Code Playgroud)

ObjectMapper:

  • 另一种方法是使用ObjectMapper.这样可以提供更多控制,但也需要更多代码.

例:

    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)
Run Code Online (Sandbox Code Playgroud)

  • @Charlie 抱歉,我不确定这是否可能。 (2认同)
  • @ Suresh:可以按照示例编写自定义转换。我将图像转换为字符串,然后添加到 Json 对象中。它有很多帮助,特别是与 watch os 一起工作 (2认同)
  • 嗨,你知道如何初始化一个 Mappable 类并手动设置属性,然后将对象转换为 jsonString 吗? (2认同)

Peh*_*eje 13

我在一个不需要继承的小型解决方案上工作了一下.但它没有经过多少测试.这是非常难看的atm.

https://github.com/peheje/JsonSerializerSwift

你可以将它传递到游乐场进行测试.例如以下类结构:

//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)
Run Code Online (Sandbox Code Playgroud)

版画

{"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"]}}
Run Code Online (Sandbox Code Playgroud)


Dow*_*oat 7

这不是一个完美/自动的解决方案,但我相信这是这样做的惯用和本地方式.这样您就不需要任何库等.

创建协议,例如:

/// 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的课程中实现它,例如:

class User: JSONSerializable {
    var id: Int
    var name: String

    var dict { return ["id": self.id, "name": self.name]  }
}
Run Code Online (Sandbox Code Playgroud)

现在:

let user = User(...)
let json = user.json()
Run Code Online (Sandbox Code Playgroud)

注意:如果你想要json一个字符串,只需转换为一个字符串:String(data: json, encoding .utf8)


dhe*_*eru 6

上面的一些答案完全没问题,但我在这里添加了一个扩展,只是为了使它更具可读性和可用性。

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!)
Run Code Online (Sandbox Code Playgroud)

//这将打印如下:

{
  "id" : 1,
  "name" : "name"
}
Run Code Online (Sandbox Code Playgroud)