Search code examples
swiftcore-data

Not able to save to CoreData. SQLCore dispatchRequest Object of class " " not among allowed top level class list


I got this error message when I tried to save the data to core data. I think it got maybe something to do that some of the attributes in my Entities are of type Transformable.

Error Message:

[error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x60000029c8f0> , Object of class Address is not among allowed top level class list (
    NSArray,
    NSDictionary,
    NSSet,
    NSString,
    NSNumber,
    NSDate,
    NSData,
    NSURL,
    NSUUID,
    NSNull
) with userInfo of (null)

Entities and their attributes in the .xcdatamodeld file (screenshots):

  1. User Entity Image Link
  2. Address Entity Image Link

User Class UPDATED:

@objc(User)
public class User: NSManagedObject, Decodable {

    private enum CodingKeys: String, CodingKey { case address, company , avatar, email, id, name, phone, username, website }

     required convenience public init(from decoder: Decoder) throws {

         guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("NSManagedObjectContext is missing") }

         let entity = NSEntityDescription.entity(forEntityName: "User", in: context)!
         self.init(entity: entity, insertInto: context)

         let values = try decoder.container(keyedBy: CodingKeys.self)

         address = try values.decode(Address.self, forKey: .address)
         avatar = try values.decode(String.self, forKey: .avatar)
         company = try values.decode(Company.self, forKey: .company)
         email = try values.decode(String.self, forKey: .email)
         id = try values.decode(Int32.self, forKey: .id)
         name = try values.decode(String.self, forKey: .name)
         phone = try values.decode(String.self, forKey: .phone)
         username = try values.decode(String.self, forKey: .username)
         website = try values.decode(String.self, forKey: .website)

     }
}

Address Class UPDATED::

@objc(Address)
public class Address: NSManagedObject, Decodable {

    private enum CodingKeys: String, CodingKey { case geo, city, street, suite, zipcode }

        required convenience public init(from decoder: Decoder) throws {

            guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("NSManagedObjectContext is missing") }

            let entity = NSEntityDescription.entity(forEntityName: "Address", in: context)!
            self.init(entity: entity, insertInto: context)

            let values = try decoder.container(keyedBy: CodingKeys.self)

                street = try values.decode(String.self, forKey: .street)
                suite = try values.decode(String.self, forKey: .suite)
                city = try values.decode(String.self, forKey: .city)
                zipcode = try values.decode(String.self, forKey: .zipcode)
                geo = try values.decode(Geo.self, forKey: .geo)
      }

}

Address Class UPDATED:

extension Address {

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

    @NSManaged public var city: String
    @NSManaged public var street: String
    @NSManaged public var suite: String
    @NSManaged public var zipcode: String
    @NSManaged public var geo: Geo

}

All suggestions and code samples are appreciated. Thanks. :)


Solution

  • Your Core Data model is wrong.

    Delete the attributes address and company. Both must be relationships.

    • Select User, click on the + sign below relationship, name it address, select Address as destination.
    • Select Address, click on the + sign below relationship, name it user, select User as destination and address as inverse.
    • Go back to User and select user as inverse of the relationship.

    Make sure that both relationships are to-one and that both @NSManaged objects are declared in the classes.

    Do the same for Company and for the other wrong Transformable attributes.

    And in init(from decoder you have to set one direction of the relationships explicitly.