Search code examples
swiftcore-data

[Core Data]:Multiple NSEntityDescriptions claim the NSManagedObject subclass 'Core Data Model' so +entity is unable to disambiguate


I am getting the following error while saving data to CoreData. I made this project completely simple for you to review my project. There is Local json in the project. You can download and test my project.

Project GitLab Link: Core Data Test Project

2021-08-20 20:17:03.576453+0300 CoreDataTest[27924:2275095] [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'QuestionCD' so +entity is unable to disambiguate.
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'QuestionCD' so +entity is unable to disambiguate.
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'.
2021-08-20 20:17:03.576675+0300 CoreDataTest[27924:2275095] [error] warning:     'QuestionCD' (0x2809142c0) from NSManagedObjectModel (0x281d33ca0) claims 'QuestionCD'.
CoreData: warning:       'QuestionCD' (0x2809142c0) from NSManagedObjectModel (0x281d33ca0) claims 'QuestionCD'.
2021-08-20 20:17:03.576720+0300 CoreDataTest[27924:2275095] [error] warning:     'QuestionCD' (0x2809148f0) from NSManagedObjectModel (0x281d4cf50) claims 'QuestionCD'.
CoreData: warning:       'QuestionCD' (0x2809148f0) from NSManagedObjectModel (0x281d4cf50) claims 'QuestionCD'.
2021-08-20 20:17:03.576762+0300 CoreDataTest[27924:2275095] [error] warning:     'QuestionCD' (0x280914fd0) from NSManagedObjectModel (0x281d4e490) claims 'QuestionCD'.
CoreData: warning:       'QuestionCD' (0x280914fd0) from NSManagedObjectModel (0x281d4e490) claims 'QuestionCD'.
2021-08-20 20:17:03.576804+0300 CoreDataTest[27924:2275095] [error] error: +[QuestionCD entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[QuestionCD entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
2021-08-20 20:17:03.585701+0300 CoreDataTest[27924:2275095] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-20 20:17:03.585897+0300 CoreDataTest[27924:2275095] -[CoreDataTest.QuestionList encodeWithCoder:]: unrecognized selector sent to instance 0x281028400
2021-08-20 20:17:03.586179+0300 CoreDataTest[27924:2275095] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-20 20:17:03.586297+0300 CoreDataTest[27924:2275095] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b0d5c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b0d5c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-20 20:17:03.586383+0300 CoreDataTest[27924:2275095] [error] error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-20 20:17:03.586553+0300 CoreDataTest[27924:2275095] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-20 20:17:03.586649+0300 CoreDataTest[27924:2275095] -[CoreDataTest.QuestionList encodeWithCoder:]: unrecognized selector sent to instance 0x281028400
2021-08-20 20:17:03.586799+0300 CoreDataTest[27924:2275095] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-20 20:17:03.586874+0300 CoreDataTest[27924:2275095] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b0d5c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b0d5c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-20 20:17:03.586942+0300 CoreDataTest[27924:2275095] [error] error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-20 20:17:03.587088+0300 CoreDataTest[27924:2275095] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-20 20:17:03.587163+0300 CoreDataTest[27924:2275095] -[CoreDataTest.QuestionList encodeWithCoder:]: unrecognized selector sent to instance 0x281028400
2021-08-20 20:17:03.587301+0300 CoreDataTest[27924:2275095] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-20 20:17:03.587372+0300 CoreDataTest[27924:2275095] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b0d5c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b0d5c0> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-20 20:17:03.587434+0300 CoreDataTest[27924:2275095] [error] error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-20 20:17:03.599299+0300 CoreDataTest[27924:2275095] [general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
2021-08-20 20:17:03.599618+0300 CoreDataTest[27924:2275095] -[CoreDataTest.QuestionList encodeWithCoder:]: unrecognized selector sent to instance 0x281028400
2021-08-20 20:17:03.599908+0300 CoreDataTest[27924:2275095] *** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
2021-08-20 20:17:03.600018+0300 CoreDataTest[27924:2275095] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b04000> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x280b04000> , <shared NSKeyedUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
Failed to save selected category: A Core Data error occurred.

Source Editor Functionality Is Limited Error (What is this ? / Why ?):

enter image description here

Core Data Entities:

enter image description here

Core Data Save Function:

func saveSelectedQuestion(questionTitle: String, id: String, questions: [QuestionList]) {
    
    let questionsCD = QuestionCD(context: persistentContainer.viewContext)
    questionsCD.title = questionTitle
    questionsCD.id = id
    questionsCD.questions = questions
    
    do {
        try persistentContainer.viewContext.save()
    } catch {
        print("Failed to save selected category: \(error.localizedDescription)")
    }
}

Model:

class QuestionContainer: NSObject, Codable {
    
    var questionCategories: [Question]
    
    init(questionCategories: [Question]) {
        self.questionCategories = questionCategories
    }
}

class Question: NSObject, Codable {
    
    var title: String
    var id: String
    var questions: [QuestionList]
    
    init(title: String, id: String, questions: [QuestionList]) {
        self.title = title
        self.id = id
        self.questions = questions
    }
}

public class QuestionList: NSObject, Codable {
    
    init(id: String, question: String, isQuestionImage: Bool, isSectionImage: Bool, imageURL: String, imageData: Data? = nil, sections: Sections, selected: String, correct: String) {
        self.id = id
        self.question = question
        self.isQuestionImage = isQuestionImage
        self.isSectionImage = isSectionImage
        self.imageURL = imageURL
        self.imageData = imageData
        self.sections = sections
        self.selected = selected
        self.correct = correct
    }
    
    var id: String
    var question: String
    var isQuestionImage, isSectionImage: Bool
    var imageURL: String
    var imageData: Data?
    var sections: Sections
    var selected: String
    var correct: String
}

public class Sections: NSObject, Codable {
    init(a: String, b: String, c: String, d: String) {
        self.a = a
        self.b = b
        self.c = c
        self.d = d
    }
    
    var a, b, c, d: String
    private enum CodingKeys: String, CodingKey {
       case a = "A"
       case b = "B"
       case c = "C"
       case d = "D"
    }
}

Page Where I Save Data:

I am saving data from this page.

struct QuestionCategoryCellView: View {
    @ObservedObject var questionCategoryCellViewModel = QuestionCategoryCellViewModel()
    var questionTitle: String
    var questionID: String
    @Binding var questions: [QuestionList]
    var body: some View {
        Button(action: {
            print("title: \(questionTitle)")
            if questionCategoryCellViewModel.searchCategoryInCoreData(id: questionID) {
                print("already saved")
            } else {
                questionCategoryCellViewModel.saveSelectedQuestionsToCoreData(questionTitle: questionTitle, id: questionID, questions: questions)
            }
        }) {
            Text(questionTitle)
        }
    }
}

Solution

  • 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,

    1. You create a QuestionCategoryCellView

    2. QuestionCategoryCellView creates a QuestionCategoryCellViewModel

    3. Every instance of QuestionCategoryCellViewModel has this property:

      let coreDM: CoreDataManager = CoreDataManager()
      
    4. Every CoreDataManager calls persistentContainer.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

    1. Add this line to CoreDataManager:

      static var shared = CoreDataManager()
      
    2. Change QuestionCategoryCellViewModel so that instead of creating a CoreDataManager, 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.