3

I am getting the following error while saving data to CoreData. my model has the dictionary property. I created NSSecureCoding and NSSecureUnarchiveFromDataTransformer classes. please check if i can encode my model correctly. I couldn't understand what I am doing wrong ? I know little English. Thank you for your understanding.

Console Output:

2021-08-21 23:58:18.490834+0300 CoreDataTest[35689:2901360] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-21 23:58:18.491043+0300 CoreDataTest[35689:2901360] [error] error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-21 23:58:18.491364+0300 CoreDataTest[35689:2901360] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-21 23:58:18.491448+0300 CoreDataTest[35689:2901360] [error] error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-21 23:58:18.491707+0300 CoreDataTest[35689:2901360] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
2021-08-21 23:58:18.491792+0300 CoreDataTest[35689:2901360] [error] error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
CoreData: error: -executeRequest: encountered exception = <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo = (null)
2021-08-21 23:58:18.503555+0300 CoreDataTest[35689:2901360] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x2827f0240> , <shared NSSecureUnarchiveFromData transformer> threw while encoding a value. with userInfo of (null)
Failed to save selected category: A Core Data error occurred.

Core Data Entity:

enter image description here

My Custom Model:

Notice my model has a Dictionary.

var sections: [QuestionSections.RawValue : String]

I am trying to save dictionary in CoreData. I thought the problem was in the dictionary but the problem is not in the dictionary.

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

public 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: [QuestionSections.RawValue : String], 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: [QuestionSections.RawValue : String]
    var selected: String
    var correct: String
}

enum QuestionSections: String, Codable {
    case A = "A"
    case B = "B"
    case C = "C"
    case D = "D"
}

NSSecure Coding:

Can you check here? Am I encoding Dictionary correctly?

var sections: [QuestionSections.RawValue : String] = [:]

class QuestionsNSSecureCoding: NSSecureCoding {
    
    static var supportsSecureCoding: Bool = true
    
    var id: String
    var question: String
    var isQuestionImage: Bool
    var isSectionImage: Bool
    var imageURL: String
    var imageData: Data?
    var sections: [QuestionSections.RawValue : String] = [:]
    var selected: String
    var correct: String
    
    required init(id: String, question: String, isQuestionImage: Bool, isSectionImage: Bool, imageURL: String, imageData: Data? = nil, sections: [QuestionSections.RawValue : String], 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
    }
    
    func encode(with coder: NSCoder) {
        coder.encode(id, forKey: "id")
        coder.encode(question, forKey: "question")
        coder.encode(isQuestionImage, forKey: "isQuestionImage")
        coder.encode(isSectionImage, forKey: "isSectionImage")
        coder.encode(imageURL, forKey: "imageURL")
        coder.encode(imageData)
        coder.encode(sections, forKey: "sections")
        coder.encode(selected, forKey: "selected")
        coder.encode(correct, forKey: "correct")
    }
    
    required init?(coder: NSCoder) {
        id = coder.decodeObject(of: NSString.self, forKey: "id") as String? ?? ""
        question = coder.decodeObject(of: NSString.self, forKey: "question") as String? ?? ""
        isQuestionImage = coder.decodeBool(forKey: "isQuestionImage")
        isSectionImage = coder.decodeBool(forKey: "isSectionImage")
        imageURL = coder.decodeObject(of: NSString.self, forKey: "imageURL") as String? ?? ""
        imageData = coder.decodeData()
        sections = coder.decodeDictionary(withKeyClass: NSString.self, objectClass: NSString.self, forKey: "sections") as [String : String]? ?? ["":""]
        selected = coder.decodeObject(of: NSString.self, forKey: "selected") as String? ?? ""
        correct = coder.decodeObject(of: NSString.self, forKey: "correct") as String? ?? ""
    }
}

NSSecure Unarchive From Data Transformer:

@objc(QuestionsValueTransformer)
class QuestionsValueTransformer: NSSecureUnarchiveFromDataTransformer {
    static let name = NSValueTransformerName(rawValue: String(describing: QuestionsValueTransformer.self))
 
    override static var allowedTopLevelClasses: [AnyClass] {
        return [QuestionsNSSecureCoding.self]
    }
    
    public static func register() {
            let transformer = QuestionsValueTransformer()
            ValueTransformer.setValueTransformer(transformer, forName: name)
        }
}

CoreData 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)")
    }
}

CoreData Manager:

class CoreDataManager {
    static var shared = CoreDataManager()
    let persistentContainer: NSPersistentContainer
    
    init() {
        persistentContainer = NSPersistentContainer(name: "QuestionsCoreData")
        QuestionsValueTransformer.register()
        persistentContainer.loadPersistentStores { description, error in
            if let error = error {
                fatalError("Core Data Stre failed: \(error.localizedDescription)")
            }
        }
    }
    
    func searchInCategory(id: String) -> [QuestionCD] {
        let fetchRequest: NSFetchRequest<QuestionCD> = QuestionCD.fetchRequest()
        let search = NSPredicate(format: "ANY id == %@", id)
        print("search: \(search)")
        fetchRequest.predicate = search
        
        do {
            return try persistentContainer.viewContext.fetch(fetchRequest)
        } catch {
            print("no Data \n")
            return []
        }
    }
    
    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)")
        }
    }
    
    func getSelectedQuestion(questionID: String) -> QuestionCD {
        let fetchRequest: NSFetchRequest<QuestionCD> = QuestionCD.fetchRequest()
        let search = NSPredicate(format: "id == %@", questionID)
        print("search: \(search)")
        fetchRequest.predicate = search
        print("request predicate: \(String(describing: fetchRequest.predicate))")
        do {
            return try persistentContainer.viewContext.fetch(fetchRequest).first ?? QuestionCD()
        } catch {
            return QuestionCD()
        }
    }
}
Ufuk Köşker
  • 1,288
  • 8
  • 29

0 Answers0