Swift: загрузка кодируемого класса в CoreData из JSON создает объекты со всеми свойствами до нуля - PullRequest
1 голос
/ 31 марта 2020

Справочная информация: Я создаю игру с возможностью покупки / использования бонусов. Я хочу предварительно загрузить эти объекты питания в базу данных CoreData с количеством 0. Идея заключается в том, что пользователь будет покупать бонусы, а затем в базе данных сохраняется контекст их количества.

Проблема: Мои объекты Codable создаются со всеми свойствами, равными нулю или 0, т.е. не принимают информацию, предоставленную JSON. Пожалуйста, вы можете помочь мне понять, где я иду не так.

Мой Codable соответствующий класс:

import Foundation
import CoreData

class PowerUp: NSManagedObject, Codable {

    enum CodingKeys: String, CodingKey {
        case name
        case desc
        case image
        case quantity
    }

    var name: String?
    var desc: String?
    var image: String?
    var quantity: Double?

    required convenience init(from decoder: Decoder) throws {
        guard let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.context,
            let context = decoder.userInfo[codingUserInfoKeyManagedObjectContext] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "PowerUp", in: context) else {
            fatalError("Failed to decode PowerUp")
        }

        self.init(entity: entity, insertInto: context)

        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decodeIfPresent(String.self, forKey: .name)
        self.desc = try container.decodeIfPresent(String.self, forKey: .desc)
        self.image = try container.decodeIfPresent(String.self, forKey: .image)
        self.quantity = try container.decodeIfPresent(Double.self, forKey: .quantity)
    }

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

public extension CodingUserInfoKey {
    // Helper property to retrieve the context
    static let context = CodingUserInfoKey(rawValue: "context")
}

Мой JSON (powerUpData. json):

[
    {
        "name": "Extra Time",
        "desc": "Wind back the clock with an extra 30 seconds.",
        "image": "sand-clock",
        "quantity": 0.0
    },
    {
        "name": "Voice Trade",
        "desc": "Offload an asset to a friend for 10% more than originally paid.",
        "image": "microphone",
        "quantity": 0.0
    }
]

Мой AppDelegate (где выполняется декодирование и предварительная загрузка):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        preloadPowerUps()
        return true
    }

// Skipped out non-edited, irrelevant AppDelegate functions for clarity...

func preloadPowerUps() {
        guard let url = Bundle.main.url(forResource: "powerUpData", withExtension: "json") else { fatalError("no file") }
        do {
            let json = try Data(contentsOf: url)
            print(json)
            let decoder = JSONDecoder()
            decoder.userInfo[CodingUserInfoKey.context!] = persistentContainer.viewContext
            do {
                let subjects = try decoder.decode([PowerUp].self, from: json)
                print(subjects)
                do {
                    try persistentContainer.viewContext.save()
                } catch {
                    print("error")
                }
            } catch {
                print("error")
            }
        } catch {
            print("error")
        }
    }

Более того, при отладке мои объекты PowerUp, похоже, принимают значения моего json, но также вид не ... AppDelegate debugging

1 Ответ

0 голосов
/ 02 апреля 2020

Подводя итоги из комментариев к комментариям:

Важно помнить, что CoreData по-прежнему сильно зависит от Objective- C. В вашем примере кода свойства вашего класса, хотя и выражаемые как атрибуты CoreData, реализация не обрабатывается CoreData.

Вам необходимо добавить атрибут @NSManaged в свои свойства, например так:

@NSManaged var name: String?
@NSManaged var desc: String?
@NSManaged var image: String?
@NSManaged var quantity: Double?

Это предоставит их Obj- C в качестве динамических c и позволит CoreData обрабатывать реализацию. Это также поможет объяснить вашу отладку, поскольку во время выполнения оператор print будет показывать значения, но сохраненный управляемый объект будет иметь значения nil.

...