问题
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)
}
回答1:
Declare photos as a swift native type
@NSManaged var photos: Set<Photo>
In decoder
photos = try values.decode(Set<Photo>.self, forKey: .photos)
来源:https://stackoverflow.com/questions/61882241/how-do-i-properly-use-codable-coredata-and-nsset-relationships