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

如何让Core Data实体类遵守NSSecureCoding协议?

解决Core Data实体类遵守NSSecureCoding的初始化错误与实现方案

错误原因解析

你遇到的Must call a designated initializer of the superclass 'NSManagedObject'错误,核心原因是:

  • NSManagedObject的唯一指定初始化器是init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?),自定义的普通初始化方法没有调用该方法。
  • @NSManaged修饰的属性由Core Data动态生成,不能在调用父类指定初始化器前直接赋值。

正确实现方案

1. 调整实体类的初始化与NSSecureCoding实现

修改PersonEntity类,移除错误的自定义初始化,改用便捷初始化方法实现属性赋值,同时规范NSSecureCoding的编码/解码逻辑:

import CoreData

@objc(PersonEntity)
public class PersonEntity: NSManagedObject, NSSecureCoding {
    public static var supportsSecureCoding: Bool = true
   
    enum Key: String {
        case id = "id"
        case name = "name"
        case gender = "gender"
        case volunteered = "volunteered"
        case entityName = "PersonEntity"
    }
   
    // 便捷初始化:传入上下文与属性值
    convenience init(context: NSManagedObjectContext, id: UUID, name: String, gender: String, volunteered: Bool) {
        guard let entity = NSEntityDescription.entity(forEntityName: Key.entityName.rawValue, in: context) else {
            fatalError("无法获取PersonEntity的实体描述")
        }
        // 必须先调用父类指定初始化器
        super.init(entity: entity, insertInto: context)
        // 初始化后再设置@NSManaged属性
        self.id = id
        self.name = name
        self.gender = gender
        self.volunteered = volunteered
    }
   
    public func encode(with coder: NSCoder) {
        coder.encode(id, forKey: Key.id.rawValue)
        coder.encode(name, forKey: Key.name.rawValue)
        coder.encode(gender, forKey: Key.gender.rawValue)
        coder.encode(volunteered, forKey: Key.volunteered.rawValue)
        // 编码实体名称,解码时需依赖它获取实体描述
        coder.encode(Key.entityName.rawValue, forKey: "entityName")
    }
   
    required public init?(coder: NSCoder) {
        // 解码实体名称与上下文(需提前实现CoreData共享栈,示例用CoreDataStack)
        guard let entityName = coder.decodeObject(forKey: "entityName") as? String,
              let context = CoreDataStack.shared.persistentContainer.viewContext,
              let entity = NSEntityDescription.entity(forEntityName: entityName, in: context) else {
            return nil
        }
        // 调用父类指定初始化器,解码时暂不插入上下文
        super.init(entity: entity, insertInto: nil)
       
        // 安全解码属性(符合NSSecureCoding要求)
        self.id = coder.decodeObject(of: UUID.self, forKey: Key.id.rawValue)
        self.name = coder.decodeObject(of: NSString.self, forKey: Key.name.rawValue) as String?
        self.gender = coder.decodeObject(of: NSString.self, forKey: Key.gender.rawValue) as String?
        self.volunteered = coder.decodeBool(forKey: Key.volunteered.rawValue)
    }
}

2. 实现对应ValueTransformer

要将PersonEntity作为transformable类型存储,需创建自定义转换器并注册:

class PersonEntityTransformer: ValueTransformer {
    override class func allowsReverseTransformation() -> Bool {
        return true
    }
   
    override class func transformedValueClass() -> AnyClass {
        return PersonEntity.self
    }
   
    override func transformedValue(_ value: Any?) -> Any? {
        guard let person = value as? PersonEntity else { return nil }
        do {
            return try NSKeyedArchiver.archivedData(withRootObject: person, requiringSecureCoding: true)
        } catch {
            print("归档PersonEntity失败:\(error)")
            return nil
        }
    }
   
    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data else { return nil }
        do {
            return try NSKeyedUnarchiver.unarchivedObject(ofClass: PersonEntity.self, from: data)
        } catch {
            print("解档PersonEntity失败:\(error)")
            return nil
        }
    }
}

// 注册转换器(可在App启动时调用)
extension PersonEntityTransformer {
    static let name = NSValueTransformerName(rawValue: "PersonEntityTransformer")
   
    static func register() {
        let transformer = PersonEntityTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }
}

3. Core Data模型配置

在Core Data模型文件中:

  • 找到需要存储PersonEntity的transformable属性,设置Transformer为PersonEntityTransformer
  • 勾选Uses Secure Coding选项

内容的提问来源于stack exchange,提问作者chan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:24:33