尝试将json解码为NSManagedObject时,给定数据不包含顶级值错误 [英] The given data did not contain a top-level value error when attempting to decode json into NSManagedObject

查看:55
本文介绍了尝试将json解码为NSManagedObject时,给定数据不包含顶级值错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将应用程序从Realm迁移到CoreData时,我试图解析以下JSON结构:

While migrating an app from Realm to CoreData, I'm attempting to parse the following JSON structure:

{
    "username": "972542052677",
    "displayName": "Arik",
    "countryCode": "972",
    "status": "Busy",
    "walletPublicKey": "XgWDiGMFRPDRVnRq8nxu7NyMLuT4Uez7mJ",
    "lastSeen": "2020-08-05T08:12:57.5267881",
    "isOnline": false
}

我需要从该数据创建一个NSManagedObject,因此我在关注本教程: https://medium.com/@andrea.prearo/使用可编码和核心数据83983e77198e

I need to create an NSManagedObject from this data so I'm following this tutorial: https://medium.com/@andrea.prearo/working-with-codable-and-core-data-83983e77198e

这是模型.它从自动生成的"ManagedProfile"继承.课:

This is the model. It inherits from the automatically generated "ManagedProfile" class:

class ManagedProfileCodable: ManagedProfile, Codable {

enum CodingKeys: String, CodingKey {
    case username           = "username"
    case displayName        = "displayName"
    case email              = "email"
    case status             = "status"
    case walletPublicKey    = "walletPublicKey"
    case countryCode        = "countryCode"
    case isOnline           = "isOnline"
    case lastSeen           = "lastSeen"
}

// MARK: - Decodable
required convenience init(from decoder: Decoder) throws {
    guard let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.managedObjectContext else{
        fatalError("Failed to get codingUserInfoKeyManagedObjectContext")
    }
    
    guard let managedObjectContext = decoder.userInfo[codingUserInfoKeyManagedObjectContext] as? NSManagedObjectContext else{
        fatalError("Failed to get context from decoder")
    }
    guard let entity = NSEntityDescription.entity(forEntityName: "ManagedProfile", in: managedObjectContext) else {
        fatalError("Failed to read entity desc")
    }
    
    self.init(entity: entity, insertInto: managedObjectContext)

    let container =     try decoder.container(keyedBy: CodingKeys.self)

    self.username =     try container.decodeIfPresent(String.self, forKey: .username)
    self.displayName =  try container.decodeIfPresent(String.self, forKey: .displayName)
    self.email =        try container.decodeIfPresent(String.self, forKey: .email)
    self.status =       try container.decodeIfPresent(String.self, forKey: .status)
    self.walletPublicKey =  try container.decodeIfPresent(String.self, forKey: .walletPublicKey)
    self.isOnline =     try container.decodeIfPresent(Bool.self, forKey: .isOnline) ?? false
    self.countryCode = try container.decodeIfPresent(String.self, forKey: .countryCode)
    
}
// MARK: - Encodable
public func encode(to encoder: Encoder) throws {
    
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(username, forKey: .username)
    try container.encode(username, forKey: .displayName)
    try container.encode(username, forKey: .email)
    try container.encode(username, forKey: .countryCode)
    try container.encode(username, forKey: .lastSeen)
    try container.encode(username, forKey: .walletPublicKey)
    try container.encode(username, forKey: .status)
    try container.encode(username, forKey: .isOnline)
}}

这是解码器:

var jsonDecoder : JSONDecoder = {
        let decoder = JSONDecoder()
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate{
            if let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.managedObjectContext{
                decoder.userInfo[codingUserInfoKeyManagedObjectContext] = appDelegate.persistentContainer.viewContext
            }
        }
        return decoder
    }()

这是进行实际解码的部分.T代表ManagedProfileCodable,并且existData变量包含一个有效的json(我使用较旧的JSONSerialization库成功对其进行了编码,以确保其有效)

This is the part that does the actual decoding. T stands for ManagedProfileCodable, and the existingData variable holds a valid json (I encoded it successfully using the older JSONSerialization library to make sure it is valid)

        do
        {
            let result = try jsonDecoder.decode(T.self, from: existingData)
            DispatchQueue.main.async{
                completionHandler(NetworkResult<T>.success(result))}
        }
        catch let error {
...
        }

这是我收到的错误:

▿valueNotFound:2个元素

▿ valueNotFound : 2 elements

  • .0:TwoVerte.ManagedProfileCodable

▿.1:上下文

  • codingPath:0个元素
  • debugDescription:给定的数据不包含顶级值."
  • underlyingError:无

我在这里遇到了另一位开发人员的未答复帖子,他对此问题进行了描述:CoreData NSManagedObject&JSON Encodable无法正常工作

I came across an unanswered post from another developer who describes this same issue over here: CoreData NSManagedObject & JSON Encodable not working

由于JSON有效并且到达了initFromDecoder内部的断点,所以我想不出任何可能导致此失败的原因.建立类的方式可能出了问题.我想知道是否还有其他人也遇到过类似的问题.

Since the JSON is valid and the break point inside the initFromDecoder is reached, I can't think of anything that might cause this failure. Probably something is wrong in the way the class is built. I wonder if anyone else has also encountered a similar issue.

推荐答案

我终于解决了这个问题.代替使用"Codegen:类定义",我应该使用"Codegen:手册".并添加如下子类:

I have finally resolved the issue. Instead using "Codegen: Class Definition", I should have used "Codegen: Manual" and add the subclass like this:

  1. 打开数据模型文件
  2. 在实体下,选择相关实体
  3. 从上方菜单中选择编辑器"->创建NSManagedObject子类...

这篇关于尝试将json解码为NSManagedObject时,给定数据不包含顶级值错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆