*** -[NSKeyedUnarchiver decodeObjectForKey:]: value for key (id) is not an object. This will become an error in the future.
First I would like to describe what I am trying to do: I perform a GET request to my API, get an array of elements and add the data I got to Core Data.
Here is my CoreData Entity:
extension PetEntity {
@nonobjc public class func fetchRequest() -> NSFetchRequest<PetEntity> {
return NSFetchRequest<PetEntity>(entityName: "PetEntity")
}
@NSManaged public var category: CategoryDTO?
@NSManaged public var id: Int64
@NSManaged public var name: String?
@NSManaged public var photoUrls: [String]?
@NSManaged public var status: String?
@NSManaged public var tags: [TagDTO]?
}
extension PetEntity : Identifiable {
}
My DTO I use to get Json data in and then map it to my model:
struct PetDTO: Codable {
var id: Int
var category: CategoryDTO?
var name: String?
var photoUrls: [String]?
var tags: [TagDTO]?
var status: StatusDTO
}
public class CategoryDTO: NSObject, Codable {
var id: Int
var name: String?
public enum CodingKeys: String, CodingKey {
case id
case name
}
public required init?(coder: NSCoder) {
id = coder.decodeObject(forKey: CodingKeys.id.rawValue) as? Int ?? 0 // error here
name = coder.decodeObject(forKey: CodingKeys.name.rawValue) as? String
}
}
extension CategoryDTO: NSSecureCoding{
public static var supportsSecureCoding: Bool{
return true
}
public func encode(with coder: NSCoder) {
coder.encode(id, forKey: CodingKeys.id.rawValue)
coder.encode(name, forKey: CodingKeys.name.rawValue)
}
}
@objc(CategoryDtoTransformer)
public final class CategoryDtoTransformer: NSSecureUnarchiveFromDataTransformer {
public static let name = NSValueTransformerName(rawValue: String(describing: CategoryDtoTransformer.self))
public override static var allowedTopLevelClasses: [AnyClass] {
return [CategoryDTO.self, NSString.self, NSArray.self]
}
@objc dynamic
public static func register() {
let transformer = CategoryDtoTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}
public class TagDTO: NSObject, Codable {
var id: Int
var name: String?
public enum CodingKeys: String, CodingKey {
case id
case name
}
public required init?(coder: NSCoder) {
id = coder.decodeObject(forKey: CodingKeys.id.rawValue) as? Int ?? 0 // Error here
name = coder.decodeObject(forKey: CodingKeys.name.rawValue) as? String
}
}
extension TagDTO: NSSecureCoding{
public static var supportsSecureCoding: Bool{
return true
}
public func encode(with coder: NSCoder) {
coder.encode(id, forKey: CodingKeys.id.rawValue)
coder.encode(name, forKey: CodingKeys.name.rawValue)
}
}
@objc(TagDtoTransformer)
public final class TagDtoTransformer: NSSecureUnarchiveFromDataTransformer {
public static let name = NSValueTransformerName(rawValue: String(describing: TagDtoTransformer.self))
public override static var allowedTopLevelClasses: [AnyClass] {
return [TagDTO.self, NSString.self, NSArray.self]
}
@objc dynamic
public static func register() {
let transformer = TagDtoTransformer()
ValueTransformer.setValueTransformer(transformer, forName: name)
}
}
enum StatusDTO: String, Codable {
case available
case sold
case pending
}
And here is my CRUD code for adding to database:
class CoreDataPetPersistance: PetPerstitenceProtocol {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func add(pet: PetDTO) {
let newPet = PetEntity(context: self.context)
newPet.id = Int64(pet.id)
newPet.name = pet.name
newPet.category = pet.category
newPet.photoUrls = pet.photoUrls
newPet.tags = pet.tags
newPet.status = pet.status.rawValue
do {
try self.context.save()
} catch {
print(error)
}
}
}
Also I have added constraints to my ID to make each pet I get from API unique and registered CategoryDTO and TagDTO in app delegate. It should be fine.
Full error I get:
CoreData: error: -executeRequest: encountered exception = Error Domain=NSCocoaErrorDomain Code=133000 "Attempt to access an object not found in store." UserInfo={objectID=0xa57351074a65fcb3 <x-coredata://FEB02FEE-9B8B-4785-82A1-263F82D4CDBC/PetEntity/p1095>} with userInfo = {
NSCocoaErrorDomain = 133000;
NSUnderlyingError = "Error Domain=NSCocoaErrorDomain Code=133000 \"Attempt to access an object not found in store.\" UserInfo={objectID=0xa57351074a65fcb3 <x-coredata://FEB02FEE-9B8B-4785-82A1-263F82D4CDBC/PetEntity/p1095>}";
}
Please help me fix this and explain why this error happens
Thanks
CodePudding user response:
There are dedicated APIs for scalar types
id = coder.decodeInt64(forKey: CodingKeys.id.rawValue)
Have a look for all available APIs
To match the types declare id
as Int64
or convert the type.