我有一个实现Swift 4的结构Codable.是否有一种简单的内置方法将该结构编码为字典?
let struct = Foo(a: 1, b: 2)
let dict = something(struct)
// now dict is ["a": 1, "b": 2]
Run Code Online (Sandbox Code Playgroud) Swift 4添加了新Codable协议.当我使用JSONDecoder它似乎要求我的Codable类的所有非可选属性在JSON中有键或它会引发错误.
使我的类的每个属性都是可选的似乎是一个不必要的麻烦,因为我真正想要的是使用json中的值或默认值.(我不希望这个属性为零.)
有没有办法做到这一点?
class MyCodable: Codable {
var name: String = "Default Appleseed"
}
func load(input: String) {
do {
if let data = input.data(using: .utf8) {
let result = try JSONDecoder().decode(MyCodable.self, from: data)
print("name: \(result.name)")
}
} catch {
print("error: \(error)")
// `Error message: "Key not found when expecting non-optional type
// String for coding key \"name\""`
}
}
let goodInput = "{\"name\": \"Jonny Appleseed\" }"
let badInput = "{}"
load(input: goodInput) …Run Code Online (Sandbox Code Playgroud) 在使用Swift4和Codable协议时,我遇到了以下问题 - 看起来没有办法允许JSONDecoder跳过数组中的元素.例如,我有以下JSON:
[
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador."
},
{
"name": "Orange"
}
]
Run Code Online (Sandbox Code Playgroud)
还有一个Codable结构:
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
Run Code Online (Sandbox Code Playgroud)
解码这个json时
let decoder = JSONDecoder()
let products = try decoder.decode([GroceryProduct].self, from: json)
Run Code Online (Sandbox Code Playgroud)
结果products是空的.这是可以预料到的,因为JSON中的第二个对象没有"points"键,而struct中points不是可选的GroceryProduct.
问题是如何允许JSONDecoder"跳过"无效对象?
假设我的Customer数据类型包含一个metadata属性,该属性可以包含客户对象中的任何JSON字典
struct Customer {
let id: String
let email: String
let metadata: [String: Any]
}
Run Code Online (Sandbox Code Playgroud)
{
"object": "customer",
"id": "4yq6txdpfadhbaqnwp3",
"email": "john.doe@example.com",
"metadata": {
"link_id": "linked-id",
"buy_count": 4
}
}
Run Code Online (Sandbox Code Playgroud)
该metadata属性可以是任意JSON映射对象.
在我NSJSONDeserialization使用新的Swift 4 Decodable协议从反序列化的JSON中转换属性之前,我仍然无法想到这样做的方法.
有人知道如何使用可解码协议在Swift 4中实现这一目标吗?
Swift 4通过Decodable协议引入了对本机JSON编码和解码的支持.我如何使用自定义键?
比如说我有一个结构
struct Address:Codable {
var street:String
var zip:String
var city:String
var state:String
}
Run Code Online (Sandbox Code Playgroud)
我可以将其编码为JSON.
let address = Address(street: "Apple Bay Street", zip: "94608", city: "Emeryville", state: "California")
if let encoded = try? encoder.encode(address) {
if let json = String(data: encoded, encoding: .utf8) {
// Print JSON String
print(json)
// JSON string is
{ "state":"California",
"street":"Apple Bay Street",
"zip":"94608",
"city":"Emeryville"
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以将它编码回一个对象.
let newAddress: Address = try decoder.decode(Address.self, from: encoded)
Run Code Online (Sandbox Code Playgroud)
但如果我有一个json对象
{
"state":"California",
"street":"Apple Bay …Run Code Online (Sandbox Code Playgroud) 这是我的JSON
{
"id": 1,
"user": {
"user_name": "Tester",
"real_info": {
"full_name":"Jon Doe"
}
},
"reviews_count": [
{
"count": 4
}
]
}
Run Code Online (Sandbox Code Playgroud)
这是我想要保存的结构(不完整)
struct ServerResponse: Decodable {
var id: String
var username: String
var fullName: String
var reviewCount: Int
enum CodingKeys: String, CodingKey {
case id,
// How do i get nested values?
}
}
Run Code Online (Sandbox Code Playgroud)
Swfit 4的新Encodable/ Decodable协议使JSON(de)序列化非常令人愉快.但是,我还没有找到一种方法可以对哪些属性进行编码以及应该解码哪些属性进行细粒度控制.
我注意到从附带的CodingKeysenum中排除属性完全排除了该属性,但有没有办法进行更细粒度的控制?
是否应该使用类继承来破坏类的可解码性.例如,以下代码
class Server : Codable {
var id : Int?
}
class Development : Server {
var name : String?
var userId : Int?
}
var json = "{\"id\" : 1,\"name\" : \"Large Building Development\"}"
let jsonDecoder = JSONDecoder()
let item = try jsonDecoder.decode(Development.self, from:json.data(using: .utf8)!) as Development
print(item.id ?? "id is nil")
print(item.name ?? "name is nil") here
Run Code Online (Sandbox Code Playgroud)
输出是:
1
name is nil
Run Code Online (Sandbox Code Playgroud)
现在,如果我反转这个,名称解码但id没有.
class Server {
var id : Int?
}
class Development : Server, Codable {
var …Run Code Online (Sandbox Code Playgroud) Codable似乎是一个非常令人兴奋的功能.但我想知道我们如何在核心数据中使用它?特别是,是否可以直接从/向NSManagedObject编码/解码JSON?
我尝试了一个非常简单的例子:
并定义Foo自己:
import CoreData
@objc(Foo)
public class Foo: NSManagedObject, Codable {}
Run Code Online (Sandbox Code Playgroud)
但是当它像这样使用时:
let json = """
{
"name": "foo",
"bars": [{
"name": "bar1",
}], [{
"name": "bar2"
}]
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let foo = try! decoder.decode(Foo.self, from: json)
print(foo)
Run Code Online (Sandbox Code Playgroud)
编译器因此错误而失败:
super.init isn't called on all paths before returning from initializer
Run Code Online (Sandbox Code Playgroud)
目标文件是定义的文件 Foo
我想我可能做错了,因为我甚至没有通过NSManagedObjectContext,但我不知道在哪里坚持下去.
核心数据是否支持Codable?
为什么我得到"类型'书签'不符合协议'可解码'"错误消息?
class Bookmark: Codable {
weak var publication: Publication?
var indexPath: [Int]
var locationInText = 0
enum CodingKeys: String, CodingKey {
case indexPath
case locationInText
}
init(publication: Publication?, indexPath: [Int]) {
self.publication = publication
self.indexPath = indexPath
}
}
Run Code Online (Sandbox Code Playgroud)
我不希望保存出版物var,因为出版物拥有书签,但书签需要知道它属于哪个出版物.Publication的解码初始化将书签引用设置为自身.