Swift: невозможно вызвать «декодирование» со списком аргументов типа «([Идея], из: данных)»

Я пытался найти лучшее решение для сохранения данных для приложения, над которым я работаю, и решил, что локально сохраненный файл JSON будет лучшим балансом между простотой и функциональностью.

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

Невозможно вызвать «декодирование» со списком аргументов типа «([Идея], из: данных)»

Любая идея, что вызывает это? Должен ли сам массив идей быть кодируемым? Тогда кодирование не должно было сработать, верно? Я делаю что-то еще не так?

Мы ценим любые предложения.

var ideas = [Idea]()

--

struct Idea: Codable {
    var title: String
    var description: String?
    var date: String
    var completed: Bool
}

--

func writeIdeasToJSON(){
    let pathDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    try? FileManager().createDirectory(at: pathDirectory, withIntermediateDirectories: true)
    let filePath = pathDirectory.appendingPathComponent("data.json")

    let json = try? JSONEncoder().encode(ideas)

    do {
        try json!.write(to: filePath)
    } catch {
        print("Failed to write JSON data: \(error.localizedDescription)")
    }
}

--

func readIdeasFromJSON(){
    do {
        let path = Bundle.main.path(forResource: "data", ofType: "json")
        let jsonData = try Data(contentsOf: URL(fileURLWithPath: path!))

        do {
            let readIdeas = try JSONDecoder().decode(ideas.self, from: jsonData)
            print(readIdeas)
        } catch let error{
            print(error.localizedDescription)
        }
    } catch let error {
        print(error.localizedDescription)
    }
}

person CristianMoisei    schedule 03.07.2019    source источник
comment
Попробуйте [Idea].self вместо ideas.self.   -  person rmaddy    schedule 04.07.2019
comment
Спасибо @rmaddy, но это приводит к сбою, который просто говорит: «Неожиданно найдено nil при развертывании необязательного значения» без каких-либо других подробностей.   -  person CristianMoisei    schedule 04.07.2019
comment
Это потому, что он исправил ошибку компилятора, и теперь вы получаете совершенно не связанную с этим ошибку времени выполнения. Скорее всего, jsonData равно нулю, потому что вашего файла на самом деле нет в пакете ресурсов вашего приложения. Это имеет смысл, потому что вы записали файл в папку «Документы». Два совершенно разных места.   -  person rmaddy    schedule 04.07.2019
comment
Хорошо, это имеет смысл. Итак, первая функция сохраняет его в папку «Документы», знаете ли вы, как правильно ссылаться на это?   -  person CristianMoisei    schedule 04.07.2019
comment
Используйте тот же код, чтобы получить путь, как и при сохранении.   -  person rmaddy    schedule 04.07.2019
comment
Кажется, это не работает, он возвращает: файл «data.json» не может быть открыт, потому что такого файла нет. Я проверил путь в обеих функциях, и он одинаков, если я использую один и тот же код.   -  person CristianMoisei    schedule 04.07.2019
comment
Подробности смотрите в моем ответе ниже.   -  person rmaddy    schedule 04.07.2019


Ответы (1)


У вас две проблемы. Во-первых, это ошибка компилятора из:

let readIdeas = try JSONDecoder().decode(ideas.self, from: jsonData)

Это должно быть:

let readIdeas = try JSONDecoder().decode([Idea].self, from: jsonData)

С этим исправлением вы получаете ошибку времени выполнения, потому что вы записали файл в папку «Документы», но пытаетесь прочитать его из пакета ресурсов приложения.

Обновите код загрузки, чтобы использовать тот же путь, который использовался для сохранения файла:

func readIdeasFromJSON(){
    do {
        let pathDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let filePath = pathDirectory.appendingPathComponent("data.json")

        let jsonData = try Data(contentsOf: filePath)
        let readIdeas = try JSONDecoder().decode([Idea].self, from: jsonData)
        print(readIdeas)
    } catch {
        print(error)
    }
}
person rmaddy    schedule 03.07.2019
comment
Это сработало, большое спасибо. Хотя, как вы указали ранее, это [Идея]. Вы не возражаете, если я спрошу, почему это так? Я думал, что расшифровываю сам массив. Это то, что я закодировал. - person CristianMoisei; 04.07.2019
comment
Переменная ideas вообще не используется при декодировании. Вы должны указать decode, какой тип декодировать. Вы не передаете ему переменную. Во всяком случае, вы могли бы использовать ideas = try JSONDecoder().decode([Idea].self, from: jsonData). - person rmaddy; 04.07.2019
comment
Я понимаю. Еще раз спасибо, что разъяснили и помогли мне. - person CristianMoisei; 04.07.2019
comment
Если я могу спросить еще об одном: есть ли способ заставить функцию принимать и другие типы объектов? Итак, идея, цель и т. д. Я попытался передать объект параметров: [Любой], но затем я получаю ту же ошибку, что и ранее. Не могу вызвать «декодирование». - person CristianMoisei; 04.07.2019
comment
Спасибо, но уже есть несколько повторяющихся вопросов с одним или двумя ответами, которые я не понимаю, и я не хочу создавать еще один. Я просто сделаю уродливое выражение if (у меня всего 3 типа) и вернусь к нему позже, когда лучше пойму дженерики. - person CristianMoisei; 04.07.2019