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

问题描述 投票:0回答:1

我正在跟踪此tutorial以使用Codable实现CoreData。一切似乎都进展顺利,但是我不知道如何对照片对象列表进行编码。您可以在下图中看到我的数据结构,并查看我当前的代码。当我尝试如下解码Pin类中的照片对象时,出现错误Referencing instance method 'encode(_:forKey:)' on 'Optional' requires that 'NSSet' conform to 'Encodable'

Photo + 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

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

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

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)

}

Schema

ios swift core-data codable
1个回答
0
投票

将照片声明为快速本机类型

@NSManaged var photos: Set<Photo>

在解码器中

photos = NSSet(array: try values.decode(Set<Photo>.self, forKey: .photos))
© www.soinside.com 2019 - 2024. All rights reserved.