Swift - 使用 Codeable 保存对象崩溃应用程序

Posted

技术标签:

【中文标题】Swift - 使用 Codeable 保存对象崩溃应用程序【英文标题】:Swift - Saving an Object with Codeable crashes app 【发布时间】:2018-09-14 10:37:52 【问题描述】:

我正在编写一个应用程序,我试图通过 Codable 将数组保存在数组中并保存到 UserDefaults,但它崩溃了,并出现以下错误:

由于未捕获的异常而终止应用程序 'NSInvalidArgumentException',原因:'-[Here.UserEntries encodeWithCoder:]: 无法识别的选择器发送到实例 0x600000649e70'

我是这样保存它的:

class UserEntries: NSObject, Codable 
    struct Question : Codable 
        var question: String
        var answer: String

        enum CodingKeys: String, CodingKey 
            case question
            case answer
        

        init(question: String, answer: String) 
            self.question = question
            self.answer = answer
        
        func encode(to encoder: Encoder) throws 
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(question, forKey: .question)
            try container.encode(answer, forKey: .answer)
        
        init(from decoder: Decoder) throws 
            let container = try decoder.container(keyedBy: CodingKeys.self)
            question = try container.decode(String.self, forKey: .question)
            answer = try container.decode(String.self, forKey: .answer)
        
    

    var date: String
    var questions: [Question]

    enum CodingKeys: String, CodingKey 
        case date
        case questions
    

    init(date: String, questions: [Question]) 
        self.date = date
        self.questions = questions
    

    func encode(to encoder: Encoder) throws 
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(date, forKey: .date)
        try container.encode(questions, forKey: .questions)
    

    required init(from decoder: Decoder) throws 
        let container = try decoder.container(keyedBy: CodingKeys.self)
        date = try container.decode(String.self, forKey: .date)
        questions = [try container.decode(Question.self, forKey: .questions)]
    

userEntry 在哪里:

let userEntry = UserEntries(date: String(todayDate), questions: [UserEntries.Question(question: q1Text, answer: q1Answer), UserEntries.Question(question: q2Text, answer: q2Answer)])

然后

UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: userEntry), forKey: "allEntries")

到底出了什么问题?我有一种感觉,我无法将数组保存在数组中,但是如何解决呢?

【问题讨论】:

你好像混淆了NSCodingCodable 【参考方案1】:

这一行:

questions = [try container.decode(Question.self, forKey: .questions)]

不正确。要获取Question 的数组,您应该解码数组[Question].self 的类型:

questions = try container.decode([Question].self, forKey: .questions)

另外,请注意Decodable/EncodableJSONDecoder/JSONEncoder 一起使用,请参阅official docs。据此,这是您需要保存的内容(编码为数据然后保存):

let jsonEncoder = JSONEncoder()
if let value = try? jsonEncoder.encode(userEntry) 
    UserDefaults.standard.set(value, forKey: "allEntries")

反之 - 获取数据,如果是,尝试解码对象:

let jsonDecoder = JSONDecoder()
if let data = UserDefaults.standard.data(forKey: "allEntries"),
   let userEntry = try? jsonDecoder.decode(UserEntries.self, from: data) 

   // here you get userEntry


例子:

let userEntry = UserEntries(date: "1 Sep 18",
    questions: [
        UserEntries.Question(question: "q1Text", answer: "q1Answer"),
        UserEntries.Question(question: "q2Text", answer: "q2Answer")
    ])

let jsonEncoder = JSONEncoder()
if let value = try? jsonEncoder.encode(userEntry) 
    UserDefaults.standard.set(value, forKey: "allEntries")


let jsonDecoder = JSONDecoder()
if let data = UserDefaults.standard.data(forKey: "allEntries"),
    let userEntry = try? jsonDecoder.decode(UserEntries.self, from: data) 

    print(userEntry.date) // 1 Sep 18

【讨论】:

@Anthony,项目数组是什么?不清楚你在说什么。 Hmmm... 好的,但是当我调试和打印解码数据时,它只给出 ,而不是 UserEntries 数组,例如[日期:“1 Sep 18”,问题(问题:“q1”,答案:“ans”)] @Anthony,请在您的问题中提供完整示例。如果没有完整的代码,我真的无法理解你想要实现的目标。 抱歉,我更新了我的问题,包括“UserEntries”中包含的内容。谢谢 啊,现在说得通了。谢谢!【参考方案2】:

要将模型设置为UserDefaults,请试试这个

 if let encoded = try? JSONEncoder().encode(value) 
    UserDefaults.standard.set(encoded, forKey: "allEntries")
 

解码:

if let data = UserDefaults.standard.value(forKey: "allEntries") as? Data 
    if let yourData = try? JSONDecoder().decode(UserEntries.self, from: data) 
        Print(yourData) 
    

【讨论】:

以上是关于Swift - 使用 Codeable 保存对象崩溃应用程序的主要内容,如果未能解决你的问题,请参考以下文章

ini Codeable.io Nginx配置

css app.codeable.io风格(时尚的chrome插件)

检查字典中的对象是不是为 Int (Swift)

使用 NSCoding Swift 保存对象时出现异常

Swift:将一个对象数组和另一个对象数组保存到 NSUserDefaults 中

保存 json 响应并将其解析为 swift 对象