Crash when accessing Object properties after decoding from JSON

扶醉桌前 提交于 2020-01-04 15:57:12

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!