Core Data Encoding Crash On Saving Context
It looks like you're trying to use this type as a Core Data transformable attribute.
Core Data transformable attributes must conform to NSCoding
. Codable
has a similar name and a similar purpose, but they are not the same and are not compatible with each other. If you want to use this type with a Core Data transformable attribute, it must conform to NSCoding
.
CoreData with transformable attribute fails on save
A transformable attribute requires a class conforming to NS(Secure)Coding
(not Codable
!) and the implementation of archiving the object(s). Note the NSSecureUnarchiveFromData
errors.
In the Swift world consider to declare the attribute as String
, encode the object to JSON with Codable
and add a computed property for the seamless conversion.
CoreData - Store an array of Tranformable objects
If you are going to unarchive an array you have to add NSArray
to the top level classes, this is how I understand the error message
override class var allowedTopLevelClasses: [AnyClass] {
return [NSArray.self, Reminder.self]
}
By the way, instead of a transformable consider to encode the array to JSON and save it as a simple String. The conversion can be performed by a computed property.
The class can be a struct with dramatically less code
public struct Reminder : Codable {
public var date: Date
public var isOn: Bool
}
In the NSManagedObject
subclass create a String
Attribute
@NSManaged public var cdReminders : String
and a computed property
var reminders : [Reminder] {
get {
return (try? JSONDecoder().decode([Reminder].self, from: Data(cdReminders.utf8))) ?? []
}
set {
do {
let reminderData = try JSONEncoder().encode(newValue)
cdReminders = String(data: reminderData, encoding:.utf8)!
} catch { cdReminders = "" }
}
}
[Core Data]:Multiple NSEntityDescriptions claim the NSManagedObject subclass 'Core Data Model' so +entity is unable to disambiguate
In your error messages there are four message pairs like this:
2021-08-20 20:17:03.576623+0300 CoreDataTest[27924:2275095] [error] warning: 'QuestionCD' (0x28090c9a0) from NSManagedObjectModel (0x281d3d400) claims 'QuestionCD'.
CoreData: warning: 'QuestionCD' (0x28090c9a0) from NSManagedObjectModel (0x281d3d400) claims 'QuestionCD'.
But if you look closely, the memory address of the model is different every time. It's 0x281d3d400
here, and it's different the other three times. That's because there are four different copies of the managed object model in memory. You're loading the model more than once and confusing Core Data. It's the same entity, but Core Data is confused about where to use it.
Looking at your code, this happens because for every cell in your table,
You create a
QuestionCategoryCellView
QuestionCategoryCellView
creates aQuestionCategoryCellViewModel
Every instance of
QuestionCategoryCellViewModel
has this property:let coreDM: CoreDataManager = CoreDataManager()
Every
CoreDataManager
callspersistentContainer.loadPersistentStores
.
As a result, every cell loads the persistent container. That should never happen. You have four cells, and every cell has its own persistent container, and each container has its own copy of the model.
Either your CoreDataManager
or the persistentContainer
need to be created only once, and then used for every cell. I'd say to go for a singleton CoreDataManager
but either would probably work.
One easy way to do that is to
Add this line to
CoreDataManager
:static var shared = CoreDataManager()
Change
QuestionCategoryCellViewModel
so that instead of creating aCoreDataManager
, it does this:let coreDM: CoreDataManager = CoreDataManager.shared
If you do that, you'll avoid this problem.
You will however run into a completely different bug in your code. Your data model uses [QuestionList]
as the type for a transformable attribute. But QuestionList
doesn't conform to NSCoding
, so that doesn't work an the app crashes. Ask a different question here about that.
Core Data exception error - Invalid fetch request: HAVING with no GROUP BY with userInfo of (null)
You are using a standard query without a GROUP BY
directive – that's what the error says – so use the standard API
request.predicate = predicate
And you can get rid of the type cast and the type annotation if you specify the generic type of the request
let request = NSFetchRequest<Affirmation>(entityName: CoreDataStrings.entityAffirmation)
...
let affirmationEntityInstances = try managedObjectContext.fetch(request)
Related Topics
Anchor Constraints Not Honored in Xcode 10/iOS 12
Does Realm Support Computed Property in Swift
Swift Bug? Calling Super Class Method When Subclass with Generic Type
Swift - Setting Calayer Bounds or Frame Not Working
<Unknown>:0: Error: Opening Import File for Module 'swift': Not a Directory
Force Refresh on Another Viewcontroller Component with Swift
How to Detect When Two Objects Touch in Spritekit
Popping Noise Between Audioqueuebuffers
Using Cfarraygetvalueatindex in Swift with Unsafepointer (Aupreset)
Swift - Scanning with Ikscannerdeviceview on Osx
Continuous Rotation of Nsimageview (So It Appears to Be Animated)
Firestore - Creating a Copy of a Collection
How to Add UIpickerview in UIalertcontroller
Swift Optionals Best Practices
How to Set a Known Position and Orientation as a Starting Point of Arkit