Ios 如何使用具有正确值的Swift在CoreData中保存解码值

Ios 如何使用具有正确值的Swift在CoreData中保存解码值,ios,swift,core-data,codable,Ios,Swift,Core Data,Codable,我们在swift中使用CoreData来存储json数据并检索它们。我们希望将json数据保存在数据库中,因此我们使用Example.json in Service.swift作为jsonData。我提供了POI模型,因为它是由XCode创建的,并且它使用可编码、解码和编码。上下文是通过依赖注入传递的,它是一个单例。该模型使用带有“NSSecureUnarchiveFromData”的Transformable作为转换器。问题是:在解码时,我可以在调试模式下看到所有属性,但当应该保存上下文时,所

我们在swift中使用CoreData来存储json数据并检索它们。我们希望将json数据保存在数据库中,因此我们使用Example.json in Service.swift作为jsonData。我提供了POI模型,因为它是由XCode创建的,并且它使用可编码、解码和编码。上下文是通过依赖注入传递的,它是一个单例。该模型使用带有“NSSecureUnarchiveFromData”的Transformable作为转换器。问题是:在解码时,我可以在调试模式下看到所有属性,但当应该保存上下文时,所有值都是“nil”。如何解决这个问题?其他型号都很相似,所以我没有包括在内。如果您需要任何其他文件或其中的任何部分,请随时询问。

问题并不完全清楚,但在使用不适用于可转换属性的值时,这听起来类似于一个常见问题。可转换文件必须符合
NSCoding
NSSecureCoding
的要求。Swift类型通常不会这样做,因为除非继承自
NSObject
,否则无法遵守这些协议。使用
Codable
不是一回事。它的用途相同,但不能与
NSCoding
互操作

在这种情况下,对JSON进行解码是可行的,但是解码后的数据无法保存,因为它无法转换


如果这里的情况与此类似,您可以将属性更改为“二进制”,然后在访问它们时进行与数据的转换。或者,尝试更改为符合
NSCoding
的类型,并坚持使用transformables。

听起来像是并发问题-您是否在后台线程上下载和处理该json?该json以前已下载,如果在添加属性的行中添加断点,我可以正确读取内容。这就是为什么我不知道自己是如何的。已设置,但在上下文中似乎为零。哪些属性使用可转换属性?@TomHarrington每个属性都不是基本类型,因此“title”、“properties”、“coordinates”。我使用模型中可以看到的类作为自定义类,例如坐标是一个几何体类,它本身就是一个模型。Title是一个字典,属性也是,但它使用any,因为可能包含另一个dict,但在实现CoreData之前,我们设法让一切正常工作,现在它必须使用它。
// Service.swift
let decoder = JSONDecoder()
            decoder.userInfo[CodingUserInfoKey.managedObjectContext] = self.coreDataManager.managedObjectContext
            do {
                _ = try decoder.decode([POI].self, from: jsonData)
                self.coreDataManager.saveContext()
                print("Saved")
            }
            catch{
                print(error.localizedDescription)
            }
// POI+CoreDataClass.swift
@objc(POI)
public class POI: NSManagedObject, Codable {
    ...
    required public convenience init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[CodingUserInfoKey.managedObjectContext] as? NSManagedObjectContext else {
            throw DecoderConfigurationError.missingManagedObjectContext
            }
        let entity = NSEntityDescription.entity(forEntityName: "POI", in: context)!
        self.init(entity: entity, insertInto: context)

        let encodedValues = try decoder.container(keyedBy: CodingKeys.self)
        
        let idString = try encodedValues.decode(String.self, forKey: .id)
        self.id = UUID.init(uuidString: idString)!
        self.externalId = try encodedValues.decode(String.self, forKey: .externalId)
        self.title = try encodedValues.decode([String:String].self, forKey: .title)
        self.coordinates = try encodedValues.decode(Geometry.self, forKey: .coordinates)
        self.author = try encodedValues.decode(String.self, forKey: .author)
        self.imageUrl = try encodedValues.decode(String.self, forKey: .imageUrl)
        self.type = try encodedValues.decode(String.self, forKey: .type)
        let propertyValues = try encodedValues.decode([String:Any].self, forKey: .properties)
        self.properties = propertyValues

    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(externalId, forKey: .externalId)
        try container.encode(title, forKey: .title)
        try container.encode(coordinates, forKey: .coordinates)
        try container.encode(author, forKey: .author)
        try container.encode(imageUrl, forKey: .imageUrl)
        try container.encode(type, forKey: .type)
        try container.encode(properties, forKey: .properties)
    }
    
    private enum CodingKeys: String, CodingKey {
        case id
        case externalId
        case title
        case coordinates
        case author
        case imageUrl
        case type
        case properties
    }
}

enum DecoderConfigurationError: Error {
  case missingManagedObjectContext
}

// POI+CoreDataProperties.swift
extension POI {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<POI> {
        return NSFetchRequest<POI>(entityName: "POI")
    }

    @NSManaged public var author: String
    @NSManaged public var coordinates: Geometry
    @NSManaged public var externalId: String
    @NSManaged public var id: UUID
    @NSManaged public var imageUrl: String
    @NSManaged public var properties: [String:Any]
    @NSManaged public var title: [String:String]
    @NSManaged public var type: String
}
// CoreDataManager.swift
...
func saveContext() {
      let context = persistentContainer.viewContext
      if context.hasChanges {
        do {
          try context.save()
        } catch {
          // The context couldn't be saved.
          let nserror = error as NSError
          fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
      }
    }
// Example.json
..
{
    "id": "0c0ef61d-9507-4400-8e5e-e7dc31a34370",
    "externalId": "node/1234567890",
    "title": {
      "de": "Küche",
      "en": "kitchen"
    },
    "coordinates": {
      "type": "Point",
      "values": [
        {
          "lat": 52.123456,
          "lon": 13.123456
        }
      ]
    },
    "author": "Authorname",
    "imageUrl": "null",
    "type": "Type",
    "properties": {
      "Website": {
        "de": "https://website.com/de"
      },
      "wheelchair": false,
      "start_date": 2020
    }
  }
  ..