如何正确使用Codable,CoreData和NSSet关系? [英] How do I properly use Codable, CoreData and NSSet relationships?

查看:84
本文介绍了如何正确使用Codable,CoreData和NSSet关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在按照

解决方案

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

  @NSManaged var照片:Set< Photo> 

在解码器中

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


I'm following this tutorial to implement CoreData with Codable. 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:

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)

}

解决方案

Declare photos as a swift native type

@NSManaged var photos: Set<Photo>

In decoder

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

这篇关于如何正确使用Codable,CoreData和NSSet关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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