NSManagedObject и Codable для класса, хранящегося в сервере и локальном хранилище - PullRequest
0 голосов
/ 22 сентября 2018

Я создаю класс, который представляет данные, которые находятся либо в локальном хранилище, либо поступают из Интернета.Во время выполнения я буду использовать запрос get, чтобы получить массив этих объектов с сервера и сравнить их с существующими в CoreData, чтобы определить новый набор объектов, которые будут использоваться для приложения и сохраняться.

Таким образом, я создал управляемый класс CoreData, который представляет мой объект как таковой, он наследует NSManagedObject.Это позволит мне иметь дело с локальным хранилищем, получая массив в хранилище и возвращая новый после завершения работы приложения.

Затем я хотел бы сделать этот класс Codable таким образом, чтобы я мог реализовать required public init(from decoder: Decoder) метод, который позволяет мне получить массив таких объектов в запросе get.JSONDecoder().decode([DataClass].self, from: data!).

Есть два способа, которыми я пытаюсь это сделать, и ни один из них не работает.

Проблемы:

У меня естьprivate enum CodingKeys: String, CodingKey {...} в области видимости класса и использование этого для кодирования прекрасно работает, но по любой причине, которая вызывает ошибку, которая говорит о том, что класс не реализует кодирование, которое я не собираюсь реализовывать.Я не уверен, почему это имеет значение.

Я могу поместить enum в область действия инициализатора, но если я это сделаю, появится новая проблема.Я должен вызвать назначенный инициализатор NSManagedObject.Это проблема, потому что для этого вызова требуется NSManagedObjectContext, которого у меня нет.

В качестве альтернативы:

Я создал метод func getDataClass(from decoder: Decoder) -> DataClass?, но это такжеприносит с собой две проблемы.Я все еще должен как-то инициализировать DataClass объект, и я понятия не имею, как перенести это в строку JSONDecoder().decode([DataClass].self, from: data!).

1 Ответ

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

Вы должны заставить DataClass соответствовать Codable.

Прежде всего создайте два расширения, чтобы иметь возможность передавать NSManagedObjectContext в словаре userInfo JSONDecoder.

extension CodingUserInfoKey {
    static let context = CodingUserInfoKey(rawValue: "context")!
}

extension JSONDecoder {
    convenience init(context: NSManagedObjectContext) {
        self.init()
        self.userInfo[.context] = context
    }
}

В следующем примере используется только один атрибут name в DataClass.
Методы Codable должны находиться в классе, а не в расширении CoreDataProperties .

class DataClass: NSManagedObject, Codable {

    private enum CodingKeys: String, CodingKey { case name }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
    }

    required convenience init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Error: NSManagedObject not specified!") }
        let entity = NSEntityDescription.entity(forEntityName: "DataClass", in: context)!
        self.init(entity: entity, insertInto: context)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
    }
}

Для использования декодера необходимо использовать инициализатор

let context = // get the managed object context
let decoder = JSONDecoder(context: context)
.
...