Ios Swift:将可编码类从JSON加载到CoreData中会生成所有属性为nil的对象

Ios Swift:将可编码类从JSON加载到CoreData中会生成所有属性为nil的对象,ios,json,swift,core-data,codable,Ios,Json,Swift,Core Data,Codable,背景: 我正在创建一个可以选择购买/使用电源的游戏。我想将这些通电对象预加载到CoreData数据库中,数量为0。其想法是,用户将购买电源,然后将他们拥有的数量的上下文保存在数据库中 问题: 生成我的可编码对象时,所有属性都为nil或0,即不接受JSON提供的信息。请你帮我看看哪里出了问题 我的可编码一致性类: import Foundation import CoreData class PowerUp: NSManagedObject, Codable { enum Coding

背景: 我正在创建一个可以选择购买/使用电源的游戏。我想将这些通电对象预加载到CoreData数据库中,数量为0。其想法是,用户将购买电源,然后将他们拥有的数量的上下文保存在数据库中

问题: 生成我的可编码对象时,所有属性都为nil或0,即不接受JSON提供的信息。请你帮我看看哪里出了问题

我的可编码一致性类:

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(powerupdatea.JSON):

My AppDelegate(解码和预加载在此完成):

更重要的是,在调试时,我的PowerUp对象看起来确实采用了json的值,但也有点不。。。

从问题和评论中总结:

重要的是要记住,CoreData仍然严重依赖Objective-C。在示例代码中,类上的属性虽然可以表示为CoreData属性,但实现并不是由CoreData处理的

您需要向属性添加
@NSManaged
属性,如下所示:

@NSManaged var name:String?
@NSVAR描述:字符串?
@NSVAR管理映像:字符串?
@NSVAR管理数量:双倍?

这将把它们作为动态对象暴露给Obj-C,并允许CoreData处理实现。这也有助于解释您的调试,因为在运行时,print语句将显示值,但保存的托管对象的值为零。

总结问题注释:

重要的是要记住,CoreData仍然严重依赖Objective-C。在示例代码中,类上的属性虽然可以表示为CoreData属性,但实现并不是由CoreData处理的

您需要向属性添加
@NSManaged
属性,如下所示:

@NSManaged var name:String?
@NSVAR描述:字符串?
@NSVAR管理映像:字符串?
@NSVAR管理数量:双倍?

这将把它们作为动态对象暴露给Obj-C,并允许CoreData处理实现。这也有助于解释您的调试,因为在运行时,print语句将显示值,但保存的托管对象具有零值。

因此
print(subjects)
给出了正确的结果?在哪里打印不正确的结果?在控制台中,打印(主题)实际打印出具有零属性的对象,如右侧框中所示。但是调试器似乎在告诉我subjects的对象实际上保存了正确的数据。是的,您在print()之后保存到CoreData,这是意料之中的。我不确定我是否会这样做,为什么您希望
print(subjects)
打印为零,即使之后保存到CoreData?您知道为什么保存不正确吗?您可能需要使用
@NSManaged
,即@NSManaged var name:String?为属性添加属性?。CoreData在解码时可能未接收到值。这可以解释为什么它们出现在打印输出中,但在保存后不在实体中。因此
print(subjects)
给出了正确的结果?在哪里打印不正确的结果?在控制台中,打印(主题)实际打印出具有零属性的对象,如右侧框中所示。但是调试器似乎在告诉我subjects的对象实际上保存了正确的数据。是的,您在print()之后保存到CoreData,这是意料之中的。我不确定我是否会这样做,为什么您希望
print(subjects)
打印为零,即使之后保存到CoreData?您知道为什么保存不正确吗?您可能需要使用
@NSManaged
,即@NSManaged var name:String?为属性添加属性?。CoreData在解码时可能未接收到值。这可以解释为什么它们出现在打印输出中,而不在保存后的实体中。
[
    {
        "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
    }
]
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")
        }
    }