Swift - сохранение объекта с помощью приложения Codeable crashes - PullRequest
0 голосов
/ 14 сентября 2018

Я пишу приложение, в котором я пытаюсь сохранить массив внутри массива через 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")

Что именно идет не так?У меня такое чувство, что я не могу сохранить массив внутри массива, но тогда как это можно исправить?

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Эта строка:

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

неверно. Чтобы получить массив Question, вам необходимо декодировать тип массива [Question].self:

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

Также обратите внимание, что Decodable / Encodable работает с JSONDecoder / JSONEncoder, см. официальные документы . В соответствии с этим, вот что вам нужно сохранить (закодировать в данные, а затем сохранить):

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
}

* * Пример тысяча двадцать-один: * * 1 022
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
}
0 голосов
/ 14 сентября 2018

Чтобы установить модель на 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) 
    }
}
...