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:
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()
}
}
}