Установка для массива DateComponents значения UserDefaults не работает

Я делаю приложение с одним представлением, которое управляет всеми задачами, над которыми я работаю. У меня есть два массива: один, в котором хранятся все имена задач, а второй показывает время завершения задач. Я назначаю оба из них UserDefaults:

var tasks = [String]()
var finishingDates = [DateComponents]()
let defaults = UserDefaults()
class ViewController: UIViewController {

    func setDefaults() {
        defaults.set(tasks, forKey: "tasks")
        defaults.set(finishingDates, forKey: "finishingDates")

    }
    override func viewDidLoad() {
        super.viewDidLoad()

        tasks = defaults.stringArray(forKey: "tasks") ?? [String]()
        finishingDates = defaults.array(forKey: "finishingDates") as? [DateComponents] ?? [DateComponents]()
    }


}

Затем я проверяю, работают ли массивы:

tasks = ["task"]
finishingDates = [DateComponents(calendar: calendar, year: 1910, month: 10, day: 1)]

setDefaults()

Однако, когда я его запускаю, приложение вылетает. В делегате приложения есть ошибка SIGABRT.

Я добавляю точку останова исключения, и она вызывается в этой строке:

defaults.set(finishingDates, forKey: "finishingDates")

Он вызывается только в этой строке, а не в строке, которая устанавливает массив String. В остальном массивы идентичны. Как я могу это решить?


person user11107712    schedule 13.07.2019    source источник
comment
Вы не можете хранить DateComponents в UserDefaults. Это не массив, словарь, строка, дата, число или данные. Это единственные типы, которые вы можете хранить.   -  person rmaddy    schedule 14.07.2019
comment
Я использовал массив DateComponents. Это должно сработать?   -  person user11107712    schedule 14.07.2019
comment
Нет, потому что DateComponents нет в списке.   -  person rmaddy    schedule 14.07.2019


Ответы (1)


Вы не можете сохранить массив объектов DateComponents непосредственно в UserDefaults, но можете сохранить его данные. DateComponents соответствует протоколу Codable, поэтому вам просто нужно закодировать / декодировать ваш массив с помощью JSONEncoder / JSONDecoder и сохранить полученные данные. Кстати, я рекомендую записать его в текстовый файл JSON вместо того, чтобы сохранять его с помощью UserDefaults:


Тестирование на игровой площадке:

var finishingDates: [DateComponents] = []
finishingDates.append(.init(calendar: .current, year: 2019, month: 7, day: 13))
finishingDates.first!.month!
do {
    let finishingDatesData = try JSONEncoder().encode(finishingDates)
    print(String(data: finishingDatesData, encoding: .utf8) ?? "")

    UserDefaults.standard.set(finishingDatesData, forKey: "finishingDates")
    print("finishingDates saved to userdefaults")

    if let data = UserDefaults.standard.data(forKey: "finishingDates") {
        let loadedDateComponents = try JSONDecoder().decode([DateComponents].self, from: data)
        print(loadedDateComponents)  // "[calendar: gregorian (fixed) year: 2019 month: 7 day: 13 isLeapMonth: false ]\n"
    }
} catch { 
     print(error) 
}

Это напечатает:

"[{" день ": 13," год ": 2019," календарь ": {" язык ": {" идентификатор ":" en_US "}," часовой пояс ": {" идентификатор ":" Америка \ / Sao_Paulo "} , "identifier": "gregorian", "minimumDaysInFirstWeek": 1, "firstWeekday": 1}, "month": 7}] \ n "

а также

"[календарь: грегорианский (фиксированный) год: 2019 месяц: 7 день: 13 isLeapMonth: false] \ n"

person Leo Dabus    schedule 13.07.2019
comment
Есть ли конкретный способ изменить массив? - person user11107712; 14.07.2019
comment
@ user11107712 Что ты имеешь в виду? Я добавляю к нему новый элемент. Если вы говорите о loadedDateComponents, просто объявите его как переменную. - person Leo Dabus; 14.07.2019
comment
Как и в случае с 1UserDefaults, вы должны ввести defaults.set(array, forKey: "key"). Есть ли у JSON нечто подобное? - person user11107712; 14.07.2019
comment
Если вы хотите записать его на диск, просто выполните do { try finishingDatesData.write(to: fileURL) } catch { print(error) } - person Leo Dabus; 14.07.2019