简体   繁体   English

如何正确使用 Codable、CoreData 和 NSSet 关系?

[英]How do I properly use Codable, CoreData and NSSet relationships?

I'm following this tutorial to implement CoreData with Codable .我正在按照本教程使用Codable实现 CoreData。 Everything seems to be going great however I cannot figure out how to encode my list of photo objects.一切似乎都很好,但是我不知道如何编码我的照片对象列表。 You can see my data structure in the image below and view my current code.您可以在下图中看到我的数据结构并查看我当前的代码。 When I try to decode the photos objects in the Pin class as below I get the error:当我尝试解码Pin class 中的照片对象时,如下所示,我收到错误:

Referencing instance method 'encode(_:forKey:)' on 'Optional' requires that 'NSSet' conform to 'Encodable'在 'Optional' 上引用实例方法 'encode(_:forKey:)' 要求 'NSSet' 符合 'Encodable'

Photo+CoreDataClass.swift照片+CoreDataClass.swift

import Foundation
import CoreData

@objc(Photo)
public class Photo: NSManagedObject, Codable {

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        do {
            try container.encode(id, forKey: .id)
            try container.encode(owner, forKey: .owner)
            try container.encode(server, forKey: .server)
            try container.encode(secret, forKey: .secret)
            try container.encode(title, forKey: .title)
            try container.encode(isPublic, forKey: .isPublic)
            try container.encode(isFriend, forKey: .isFriend)
            try container.encode(isFamily, forKey: .isFamily)
        }
    }

    required convenience public init(from decoder: Decoder) throws {
        guard let contextUserInfoKey = CodingUserInfoKey(rawValue: "context"),
            let managedObjectContext = decoder.userInfo[contextUserInfoKey] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "Photo", in: managedObjectContext) else {
                fatalError("Cannot decode Photo!")
        }
        self.init(entity: entity, insertInto: managedObjectContext)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        do {
            id = try values.decode(Int64.self, forKey: .id)
            owner = try values.decode(String?.self, forKey: .owner)
            server = try values.decode(String?.self, forKey: .server)
            secret = try values.decode(String?.self, forKey: .secret)
            title = try values.decode(String?.self, forKey: .title)
            isPublic = try values.decode(Int16.self, forKey: .isPublic)
            isFriend = try values.decode(Int16.self, forKey: .isFriend)
            isFamily = try values.decode(Int16.self, forKey: .isFamily)
        } catch {
            print(error)
        }
    }

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case owner = "owner"
        case server = "server"
        case secret = "secret"
        case title = "title"
        case isPublic = "ispublic"
        case isFriend = "isfriend"
        case isFamily = "isfamily"
    }

}

Photo+CoreDataProperties.swift照片+CoreDataProperties.swift

import Foundation
import CoreData


extension Photo {

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

    @NSManaged public var id: Int64
    @NSManaged public var owner: String?
    @NSManaged public var secret: String?
    @NSManaged public var server: String?
    @NSManaged public var title: String?
    @NSManaged public var isPublic: Int16
    @NSManaged public var isFriend: Int16
    @NSManaged public var isFamily: Int16

}

Pin+CoreDataClass.swift引脚+CoreDataClass.swift

import Foundation
import CoreData

@objc(Pin)
public class Pin: NSManagedObject, Codable {

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(latitude, forKey: .latitude)
        try container.encode(longitude, forKey: .longitude)
        try container.encode(photos, forKey: .photos)
    }

    required convenience public init(from decoder: Decoder) throws {
        guard let contextUserInfoKey = CodingUserInfoKey(rawValue: "context"),
            let managedObjectContext = decoder.userInfo[contextUserInfoKey] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "Pin", in: managedObjectContext) else {
                fatalError("Could not decode Pin!")
        }
        self.init(entity: entity, insertInto: managedObjectContext)
        let values = try decoder.container(keyedBy: CodingKeys.self)
        do {
            latitude = try values.decode(Double.self, forKey: .latitude)
            longitude = try values.decode(Double.self, forKey: .longitude)
            photos = NSSet(array: try values.decode([Photo].self, forKey: .photos))
        } catch {
            print(error)
        }
    }

    enum CodingKeys: String, CodingKey {
        case latitude = "latitude"
        case longitude = "longitude"
        case photos = "photos"
    }

}

Pin+CoreDataProperties.swift Pin+CoreDataProperties.swift

import Foundation
import CoreData


extension Pin {

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

    @NSManaged public var latitude: Double
    @NSManaged public var longitude: Double
    @NSManaged public var photos: NSSet?

}

// MARK: Generated accessors for photos
extension Pin {

    @objc(addPhotosObject:)
    @NSManaged public func addToPhotos(_ value: Photo)

    @objc(removePhotosObject:)
    @NSManaged public func removeFromPhotos(_ value: Photo)

    @objc(addPhotos:)
    @NSManaged public func addToPhotos(_ values: NSSet)

    @objc(removePhotos:)
    @NSManaged public func removeFromPhotos(_ values: NSSet)

}

架构

Declare photos as a swift native type将照片声明为 swift 原生类型

@NSManaged var photos: Set<Photo>

In decoder在解码器中

photos = try values.decode(Set<Photo>.self, forKey: .photos)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM