JSON序列化后子类属性崩溃

时间:2018-06-30 18:55:51

标签: json swift serialization

我有最奇怪的问题。执行JSON序列化并创建对象后,尝试访问子类的任何属性时代码会崩溃。当我尝试访问对象超类的属性时,它们将被正确打印。

这是课程:

import UIKit

class Patient: Person {
    var approved: Bool
    var doctorId: Int

    private enum CodingKeys: String, CodingKey {
        case approved
        case doctorId
    }

    init(id: String, name: String, lastName: String, phoneNumber: String, email: String, imageURL:URL, approved:Bool, doctorId:Int) {
        self.approved = approved
        self.doctorId = doctorId
        super.init(id: id, firstName: name, lastName: lastName, imageURL: imageURL)
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.approved  = try values.decode(Bool.self, forKey: .approved)
        self.doctorId = try values.decode(Int.self, forKey: .doctorId)
        try super.init(from: decoder)
    }

    var description: String {
        return "\(type(of: self)) - (\(self.firstName), \(self.lastName))" //superclass properties 
    }
}

struct PatientsList : Codable {
    let patients: [Patient]
}

人员班:

class Person: Codable {
    let firstName: String
    let lastName: String
    let imageURL: URL?
    let id: String

    private enum CodingKeys: String, CodingKey {
        case firstName
        case lastName
        case imageURL = "profileImgPath"
        case id = "_id"
    }

    init(id: String, firstName: String, lastName: String, imageURL:URL) {
        self.id = id
        self.firstName = firstName
        self.lastName = lastName
        self.imageURL = imageURL
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.id = try values.decode(String.self, forKey: .id)
        self.firstName = try values.decode(String.self, forKey: .firstName)
        self.lastName = try values.decode(String.self, forKey: .lastName)
        self.imageURL = try values.decodeIfPresent(URL.self, forKey: .imageURL)
    }
}

这是我执行序列化的方式:

do {
                    let jsonData = try JSONSerialization.data(withJSONObject: JSON, options: [])
                    let decoder = JSONDecoder()
                    let patientList = try! decoder.decode(PatientsList.self, from: jsonData)
                    completionBlock(.success(patientList.patients))
                } catch {
                    print(error.localizedDescription)
                }

这里是     //在控制台中:po(Patient.approved)打印false     //在控制台中:表达式dump(患者)

  

▿iHeal.Patient#0▿超级:iHeal.Person

firstName: "Sarah"

lastName: "Connor"

imageURL: nil

id: "5b367491052aaca6489e4805"
     

生日:“ 1980-06-10T00:00:00.000Z”

     

已批准:错误

     

doctorId:12

print(patient.approved) //crash
print(patient.doctorId) // if I comment out previous line, this one crashes
  

线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x200000002)

我能提到的另一件奇怪的事:患者上没有描述。

print(patient) // prints plain: <Patient: 0x608000141c30>

Json:

{
    "patients": [
        {
            "approved": false,
            "_id": "5b367491052aaca6489e4805",
            "birthDate": "1980-06-10T00:00:00.000Z",
            "doctorId": 12,
            "firstName": "Sarah",
            "lastName": "Connor"
        },
        {
            "approved": false,
            "drains": [],
            "_id": "5b3674e5052aaca6489e66b3",
            "__v": 0,
            "birthDate": "1980-06-10T00:00:00.000Z",
            "doctorId": 12,
            "firstName": "Sarah",
            "lastName": "Connor"
        }
    ]
}

4 个答案:

答案 0 :(得分:2)

重复的:Crash when accessing Object properties after decoding from JSON

从基类即Person中删除了Codable一致性,但是您仍然可以通过保留要从子类中调用的带有docoder的init方法来解码基类成员。子类现在将符合Codable。

答案 1 :(得分:0)

我认为我也有类似的问题,实际上是nil,但是当您在控制台中打印它时,它返回false。尝试在print(patient.approved)之前添加一个断点,然后在控制台expression patient.approved = false中输入一个断点,看看它是否崩溃了(从该刹车点继续之后)。如果没有,那么你知道出了什么问题。

答案 2 :(得分:0)

您可以使用以下代码尝试使用if let条件来防止应用崩溃:

if let isApproved = patient.approved {
    print(isApproved)
}

此代码将检查approved属性的nil条件,它将检查属性是否为nil,然后将值分配给isApproved参数,否则条件将消失并且代码不会在if block内部执行。

这将是防止崩溃的更好解决方案。

答案 3 :(得分:0)

您应该发布JSON及其解析方式。

中的一个最小示例
import Cocoa

let jsonData = """
{
    "doctorId": 12345,
    "approved": false
}
""".data(using: .utf8)!

struct Patient : Codable {
    var approved: Bool
    var doctorId: Int
}

do {
    let patient = try JSONDecoder().decode(Patient.self, from:jsonData)
    print(patient)
} catch {
    print(error)
}
只要遵循JSON约定,

就会为您提供布尔值的无故障解析。您必须提供以上信息,才能使答案更具体。

更新

不幸的是,重现错误仍然不容易。我尝试过

import Cocoa

let jsonData = """
{
    "patients": [
        {
            "approved": false,
            "drains": [],
            "_id": "5b367491052aaca6489e4805",
            "user": {
                "_id": "5b36747d28c1c608808274ce",
                "email": "17@iheal.com"
            },
            "__v": 0,
            "birthDate": "1980-06-10T00:00:00.000Z",
            "doctorId": 12,
            "firstName": "Sarah",
            "lastName": "Connor",
            "phoneNum": "123"
        },
        {
            "approved": false,
            "drains": [],
            "_id": "5b3674e5052aaca6489e66b3",
            "user": {
                "_id": "5b3674e428c1c608808274cf",
                "email": "18@iheal.com"
            },
            "__v": 0,
            "birthDate": "1980-06-10T00:00:00.000Z",
            "doctorId": 12,
            "firstName": "Sarah",
            "lastName": "Connor",
            "phoneNum": "123"
        }
    ]
}
""".data(using: .utf8)!

struct Patient : Codable {
    var approved: Bool
    var doctorId: Int
}

struct PatientList: Codable{
    let patients: [Patient]
}

do {
    let patients = try JSONDecoder().decode(PatientList.self, from:jsonData)
    print(patients)
} catch {
    print(error)
}

但是这仍然没有任何问题。据我所知,我将不得不猜测您的Person类是什么样子,但很可能是Codable。坦白地说,我确实有继承Codable类型的经验,但是您的方法看起来并不合理。但是 很难判断您的Person类是否不是问题的一部分(当前形式的JSON解析也不是)。恐怕您必须发布这些内容才能获得有意义的答复。