英文:
How to use different keys in input and output when using Encodable protocol?
问题
Expected this: name
-> fullname
But the reality that second output produce this:
{
"name" : "John"
}
英文:
Expected this: name
-> fullname
struct Person: Codable {
let name: String
enum CodingKeys: String, CodingKey {
case name = "fullname"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
}
}
let jsonString = """
{
"name": "John"
}
"""
let jsonDecoder = JSONDecoder()
if let jsonData = jsonString.data(using: .utf8),
let decodedPerson = try? jsonDecoder.decode(Person.self, from: jsonData) {
print(decodedPerson.name) // Output: "John"
}
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
if let encodedData = try? jsonEncoder.encode(decodedPerson),
let encodedString = String(data: encodedData, encoding: .utf8) {
print(encodedString)
}
But the reality that second output produce this:
{
"name" : "John"
}
答案1
得分: 1
If your goal is to decode the name
key and output the fullname
key, you should update the CodingKeys
as follows:
enum CodingKeys: String, CodingKey {
case fullname = "fullname"
case name = "name"
}
And modify the encode
method to use .fullname
instead of .name
. Your code should look like this:
struct Person: Codable {
let name: String
enum CodingKeys: String, CodingKey {
case fullname = "fullname"
case name = "name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .fullname) // Use fullname
}
}
let jsonString = """
{
"name": "John"
}
"""
do {
let jsonData = jsonString.data(using: .utf8)!
let jsonDecoder = JSONDecoder()
let decodedPerson = try jsonDecoder.decode(Person.self, from: jsonData)
print(decodedPerson.name)
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let encodedData = try jsonEncoder.encode(decodedPerson)
let encodedString = String(data: encodedData, encoding: .utf8)!
print(encodedString)
} catch {
print(error)
}
The output will be:
John
{
"fullname" : "John"
}
However, please note that with these changes, your Person
class can't decode the JSON it encodes. This might not be what you want.
英文:
If your goal is to decode the name
key and output the fullname
key (which is really confusing and means your code can't decode the JSON that it generates) then you need to update the CodingKeys
to:
enum CodingKeys: String, CodingKey {
case fullname = "fullname"
case name = "name"
}
and you need to update the encode
method to use .fullname
instead of .name
.
Then you can parse the original JSON with the name
key and then generate new JSON with a fullname
key.
Here's your code with some cleanup and the changes I suggest:
struct Person: Codable {
let name: String
enum CodingKeys: String, CodingKey {
case fullname = "fullname"
case name = "name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .fullname) // Use fullname
}
}
let jsonString = """
{
"name": "John"
}
"""
do {
let jsonData = jsonString.data(using: .utf8)! // this can't fail
let jsonDecoder = JSONDecoder()
let decodedPerson = try jsonDecoder.decode(Person.self, from: jsonData)
print(decodedPerson.name) // Output: "John"
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let encodedData = try jsonEncoder.encode(decodedPerson)
let encodedString = String(data: encodedData, encoding: .utf8)! // This won't fail either
print(encodedString)
} catch {
print(error)
}
The output is:
>John
{
"fullname" : "John"
}
Just to reiterate. This is a bad idea. Your Person
class, with these changes, can't decode the JSON that it encodes. Are you really sure that is what you want?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论