Swift - 使用 Codeable 保存对象会导致应用程序崩溃
Swift - Saving an Object with Codeable crashes app
我正在编写一个应用程序,我试图通过 Codable 将数组保存在数组中并保存到 UserDefaults
,但它崩溃了,并出现以下错误:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[Here.UserEntries
encodeWithCoder:]: unrecognized selector sent to instance
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")
到底出了什么问题?我有一种感觉,我不能在数组中保存一个数组,但是这怎么能解决呢?
要将模型设置为 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)
}
}
这一行:
questions = [try container.decode(Question.self, forKey: .questions)]
不正确。要获得 Question
的数组,您应该解码数组的类型 [Question].self
:
questions = try container.decode([Question].self, forKey: .questions)
另外,请注意 Decodable
/Encodable
与 JSONDecoder
/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
}
我正在编写一个应用程序,我试图通过 Codable 将数组保存在数组中并保存到 UserDefaults
,但它崩溃了,并出现以下错误:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Here.UserEntries encodeWithCoder:]: unrecognized selector sent to instance 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")
到底出了什么问题?我有一种感觉,我不能在数组中保存一个数组,但是这怎么能解决呢?
要将模型设置为 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)
}
}
这一行:
questions = [try container.decode(Question.self, forKey: .questions)]
不正确。要获得 Question
的数组,您应该解码数组的类型 [Question].self
:
questions = try container.decode([Question].self, forKey: .questions)
另外,请注意 Decodable
/Encodable
与 JSONDecoder
/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
}