【问题标题】:How to save decoded values in CoreData using Swift with proper values如何使用具有正确值的 Swift 在 CoreData 中保存解码值
【发布时间】:2020-10-08 13:03:12
【问题描述】:
// 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
    }
  }
  ..

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

【问题讨论】:

  • 听起来像是一个并发问题 - 您是在后台线程上下载和处理该 json 吗?
  • 该json是之前下载的,如果我在添加属性的行中添加断点,我可以正确读取内容。这就是为什么我无法弄清楚 self. 是如何设置的,但在上下文中似乎为零。
  • 哪些属性或属性使用可转换属性?
  • @TomHarrington 每个不是基本类型的属性,例如“标题”、“属性”、“坐标”。我使用您在模型中可以看到的类作为自定义类,例如坐标是一个几何类,它本身就是一个模型。 Title 是字典,属性也是,但它使用 any 因为可能包含另一个字典,但我们在实现 CoreData 之前设法让一切正常工作,现在它必须与它一起工作。

标签: ios swift core-data codable


【解决方案1】:

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

发生这种情况时,可以对 JSON 进行解码,但解码后的数据不会被保存,因为它无法转换。

如果这里看起来是这种情况,您可以将属性更改为“二进制”,然后在访问它们时自行与Data 进行转换。或者,尝试更改为符合NSCoding 的类型并坚持使用可转换对象。

【讨论】:

    猜你喜欢
    • 2020-04-25
    • 2022-01-16
    • 1970-01-01
    • 2019-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    相关资源
    最近更新 更多