Core Data保存自定义模型报NSKeyedUnarchiveFromData相关错误如何解决?
问题根源
- 报错核心是
QuestionList类未实现NSCoding协议:Core Data的Transformable类型默认使用NSKeyedArchiver做序列化,要求存储的对象遵守NSCoding协议,你当前只给模型加了Codable协议,缺失NSCoding的实现方法,所以触发unrecognized selector sent to instance错误。 NSKeyedUnarchiveFromData警告是该旧转换器已被苹果标记为废弃,后续会被移除,需要替换为新的安全转换器。- 你提到的
[QuestionSections.RawValue : String]类型完全支持存储,本质就是[String:String]系统标准字典,本身兼容序列化规则,不是问题诱因。
修复步骤
方案1:给自定义模型添加NSCoding实现(适配默认Transformable逻辑)
给QuestionList类补充NSCoding协议的实现代码即可:
public class QuestionList: NSObject, Codable, NSCoding { // 原有属性和初始化方法保持不变 public 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, forKey: "imageData") coder.encode(sections, forKey: "sections") coder.encode(selected, forKey: "selected") coder.encode(correct, forKey: "correct") } public required init?(coder: NSCoder) { guard let id = coder.decodeObject(forKey: "id") as? String, let question = coder.decodeObject(forKey: "question") as? String, let imageURL = coder.decodeObject(forKey: "imageURL") as? String, let sections = coder.decodeObject(forKey: "sections") as? [String:String], let selected = coder.decodeObject(forKey: "selected") as? String, let correct = coder.decodeObject(forKey: "correct") as? String else { return nil } self.id = id self.question = question self.isQuestionImage = coder.decodeBool(forKey: "isQuestionImage") self.isSectionImage = coder.decodeBool(forKey: "isSectionImage") self.imageURL = imageURL self.imageData = coder.decodeObject(forKey: "imageData") as? Data self.sections = sections self.selected = selected self.correct = correct } }
如果使用该方案,建议同步在Core Data的Entity属性配置里,把questions属性的Transformer设置为NSSecureUnarchiveFromDataTransformer,即可消除废弃转换器的警告。
方案2:使用Codable转Data存储(更适配Swift生态,规避NSCoding问题)
你也可以把questions属性在Core Data中设置为Binary Data类型,存储时手动用JSONEncoder把[QuestionList]转成Data,读取时用JSONDecoder转回模型,不用修改原有模型定义:
1. 修改Core Data Entity配置
把questions字段的类型从Transformable改为Binary Data
2. 改写CoreDataManager的存储读取逻辑
// 存储时转换为Data func saveSelectedQuestion(questionTitle: String, id: String, questions: [QuestionList]) { let questionsCD = QuestionCD(context: persistentContainer.viewContext) questionsCD.title = questionTitle questionsCD.id = id do { let questionsData = try JSONEncoder().encode(questions) questionsCD.questions = questionsData try persistentContainer.viewContext.save() } catch { print("Failed to save selected category: \(error.localizedDescription)") } } // 读取时转换回模型数组 func getSelectedQuestionModels(questionID: String) -> [QuestionList]? { let fetchRequest: NSFetchRequest<QuestionCD> = QuestionCD.fetchRequest() fetchRequest.predicate = NSPredicate(format: "id == %@", questionID) do { guard let cdObj = try persistentContainer.viewContext.fetch(fetchRequest).first, let questionsData = cdObj.questions as? Data else { return nil } return try JSONDecoder().decode([QuestionList].self, from: questionsData) } catch { print("Fetch error: \(error)") return nil } }
内容的提问来源于stack exchange,提问作者Ufuk Köşker
相关产品推荐
相关产品推荐

