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


81

这个下课

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

需要转换为

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

我尝试将对象手动传递给将变量设置为字典并返回字典的函数。但我希望有一种更好的方法来实现这一目标。


1
最好的选择是运行它,并将其保存到数组和字典中,然后进行转换。
计划性的


@Schemetrical您能给我指出一个例子吗?我不知道如何遍历对象。
Penkey Suresh

好吧,您需要遍历对象本身,获取所有值,然后将其手动添加到字典中,然后重复。
计划性的

@Schemetrical我实际上尝试过。但是对于大型对象,编译时间会急剧增加。
Penkey Suresh

Answers:


126

在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 secondDog = try jsonDecoder.decode(Dog.self, from: jsonData)

21
编码类型应为.utf8而不是.utf16
Chan Jing Hong

2
@ChanJingHong这取决于您要编码的内容
Etgar

对于此特定示例,.utf16是否有效?我试过了,但是没有用。
Chan Jing Hong

@ChanJingHong Strange,我在3个月前尝试了一下,而且效果很好。我认为我应该在解码方法中也将编码类型作为参数。我会检查一下。
Etgar's

2
问题特别是关于编码class(我需要)不是struct
贡多

37

现在,与Swift 4(基础)一起都以两种方式原生支持它:对象的JSON字符串-对象为JSON字符串。请在此处JSONDecoder()和在此处JSONEncoder()参阅Apple的文档。

JSON字符串到对象

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

将对象转换为JSONString

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

您可以在此处找到所有详细信息和示例,使用Swift 4进行JSON解析的终极指南。


25

更新: Codable在大多数JSON解析情况下,Swift 4中引入的协议就足够了。以下答案适用于因早期原因而停留在Swift早期版本中的用户

EVReflection

  • 这是反映原理的作品。这需要更少的代码,同时还支持NSDictionaryNSCodingPrintableHashableEquatable

例:

    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

  • 另一种方法是使用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)

它也支持映射图像吗?
查理

1
@查理很抱歉,我不确定是否可行。
Penkey Suresh 2015年

1
@ Suresh:可以通过编写自定义转换(如示例所示)来实现。我将图像转换为String,然后添加到Json对象中。特别有助于配合手表操作系统
Charlie

1
嗨,您知道如何初始化Mappable类并手动设置属性,然后将对象转换为jsonString吗?
VAAA

swift 4 / ios 11中的可编码协议有什么影响?。我们可以使用此方法在swift 4中将NSManagedObject转换为JSON吗?
user1828845

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)

版画

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

您能提供其迅速的2.3版本吗?
H拉瓦尔

8

这不是一个完美的/自动的解决方案,但我相信这是惯用的,本机的方法。这样,您不需要任何库等。

创建一个协议,例如:

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

然后在您的类中实现它,例如:

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

    var dict { return ["id": self.id, "name": self.name]  }
}

现在:

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

注意:如果要json作为字符串,很简单地将其转换为字符串:String(data: json, encoding .utf8)


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

//这将如下所示打印:

{
  "id" : 1,
  "name" : "name"
}

2

不确定lib / framework是否存在,但是如果您想自动执行它并且希望避免体力劳动,请:-)坚持使用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
  }

}

举一个粗略的例子,缺乏适当的转换支持,缺乏递归,……这只是MirrorType演示……

PS这是在中完成的U,但是您将进行增强NSManagedObject,然后就可以转换所有NSManagedObject子类。无需在所有子类/托管对象中实现此功能。


嗨,我正在尝试这种方法,但是每当我得到0作为计数时。您能具体说明我应该做什么吗?我认为@NSManaged引起了问题。如何增强NSManagedObject?
Penkey Suresh

没有尝试过@NSManaged。可能是造成您的问题。在这种情况下,我将用Objective-C编写它,然后在Swift中使用它。
zrzka 2015年

0

2020 | SWIFT 5.1:

(也适用于SWIFT 4)


准备工作解决方案!

用法:

var msgTemplates = [msgTemlate]()

// load from file
msgTemplates = try! Serializer.load(from: url)!

// save to file
Serializer.save(data: msgTemplates, to: url)

以下代码解决了三件事:

  • 1个字符串以保存文件
  • 1个字符串以加载文件
  • 具有获取/打印某些Codable元素的JSON的能力 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:andofc数据必须是可编码的:

struct msgTemlate: Codable { 
     //some params
}

PS2:如果msgTemlate有枚举,则它们也必须是可编码的


0
struct User:Codable{
 var id:String?
 var name:String?
 init(_ id:String,_ name:String){
   self.id  = id
   self.name = name
 }
}

现在只要像这样使你的物体

让用户= User(“ 1”,“ pawan”)

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

然后从json转换为Object

let jsonDecoder = JSONDecoder()
do{
   let convertedUser = try jsonDecoder.decode(User.self, from: userJson.data(using: .utf8)!)
 }catch{
   
 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.