You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 18:09:03