问题
I have decodes JSON value into object. The object looks as expected, but when I try to access it's property.
let jsonData = try JSONSerialization.data(withJSONObject: JSON, options: [])
let decoder = JSONDecoder()
let doctor = try! decoder.decode(Doctor.self, from: jsonData)
let txt = "\(doctor.title). \(doctor.firstName) \(doctor.lastName)" // Runtime crash: (Thread 1: EXC_BAD_ACCESS (code=1, address=0x40))
Runtime crash: (Thread 1: EXC_BAD_ACCESS (code=1, address=0x40))
Class Person:
import UIKit
class Person: Codable {
let firstName: String
let lastName: String
let imageURL: URL
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
case imageURL = "profileImgPath"
}
init(firstName: String, lastName: String, imageURL:URL) {
self.firstName = firstName
self.lastName = lastName
self.imageURL = imageURL
}
}
Class Doctor:
import UIKit
class Doctor: Person {
var title: String
private enum CodingKeys: String, CodingKey {
case title
}
init(firstName: String, lastName: String, imageURL:URL, title: String) {
self.title = title
super.init(firstName: firstName, lastName: lastName, imageURL: imageURL)
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.title = try values.decode(String.self, forKey: .title)
try super.init(from: decoder)
}
}
回答1:
When i tried your code, it produced the same error and upon investigation, i found that this is an issue in Swift 4.1
. You can check below,
https://bugs.swift.org/browse/SR-7090
Possible solution for now could be a slight rearrangement as below,
Remove Codable
conformance from base class i.e Person
but you can still decode the base class members by keeping the init
method with docoder
to be called from the child classes. Child classes will conform to Codable
now.
class Person {
let firstName: String
let lastName: String
let imageURL: URL
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
case imageURL = "profileImgPath"
}
init(firstName: String, lastName: String, imageURL:URL) {
self.firstName = firstName
self.lastName = lastName
self.imageURL = imageURL
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.firstName = try values.decode(String.self, forKey: .firstName)
self.lastName = try values.decode(String.self, forKey: .lastName)
self.imageURL = try values.decode(URL.self, forKey: .imageURL)
}
}
class Doctor: Person, Codable {
var title: String
private enum CodingKeys: String, CodingKey {
case title
}
init(firstName: String, lastName: String, imageURL:URL, title: String) {
self.title = title
super.init(firstName: firstName, lastName: lastName, imageURL: imageURL)
}
required override init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.title = try values.decode(String.self, forKey: .title)
try super.init(from: decoder)
}
}
Now, if you have the following json, it will work as intended.
let json = """
{
"title":"SomeTitle",
"firstName": "SomeFirstName",
"lastName": "SomeLastName",
"profileImgPath": "urlPath"
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let doctor = try! decoder.decode(Doctor.self, from: json)
print(doctor.firstName)
print(doctor.lastName)
print(doctor.title)
来源:https://stackoverflow.com/questions/51004441/crash-when-accessing-object-properties-after-decoding-from-json