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

升级macOS 15后CoreData Transformable属性失效求助

问题描述

fault: Could not materialize Objective-C class for declared attribute value class name "ContactContainer" of attribute named contactContainer
CoreData: fault: Could not materialize Objective-C class for declared attribute value class name "ContactContainer" of attribute named contactContainer
CoreData: fault: Could not materialize Objective-C class for declared attribute value class name "ContactContainer" of attribute named contactContainer

升级至新系统版本前一切正常,不确定是否是系统设置变更导致问题。已尝试重装整机、重启、清理缓存、重装Xcode、从零重装应用、恢复Time Machine备份、删除容器等操作,但应用完全无法运行,无法登录也无法打开任何窗口。

Transformer类代码

import Foundation

@objc(ContactValueTransformer)
public final class ContactValueTransformer: ValueTransformer {

    static let name = NSValueTransformerName(rawValue: String(describing: ContactValueTransformer.self))
    
    override public class func transformedValueClass() -> AnyClass {
        ContactContainer.self
    }
    
    override public class func allowsReverseTransformation() -> Bool {
        true
    }
    
    override public func transformedValue(_ value: Any?) -> Any? {
        guard let contact = value as? ContactContainer else { return nil }
        
        do {
            let data = try JSONEncoder().encode(contact)
            return data
        } catch {
            assertionFailure("Failed to transform `ContactContainer` to `Data`")
            return nil
        }
    }
    
    override public func reverseTransformedValue(_ value: Any?) -> Any? {
        if value == nil { return nil }
        guard let data = value as? Data else { return nil }
        
        do {
            return try JSONDecoder().decode(ContactContainer.self, from: data)
        } catch {
            assertionFailure("Failed to transform `Data` to `ContactContainer`")
            return nil
        }
    }
    
    /// Registers the value transformer with `ValueTransformer`.
    public static func register() {
        let transformer = ContactValueTransformer()
        ValueTransformer.setValueTransformer(transformer, forName: name)
    }

}

ContactContainer类代码

import Foundation
import SwiftUI

public class ContactContainer: NSObject, Codable, ObservableObject {
    
    public var phones: [Phone] = [] {
        didSet {
            lastModified = .now
            objectWillChange.send()
        }
    }
    
    public var emails: [Email] = [] {
        didSet {
            lastModified = .now
            objectWillChange.send()
        }
    }
    
    public var addresses: [Address] = [] {
        didSet {
            lastModified = .now
            objectWillChange.send()
        }
    }
        
    private enum CodingKeys: CodingKey {
        case phones
        case emails
        case addresses
        case lastModified
        case dateCreated
    }
    
    public private(set) var lastModified: Date
    public private(set) var dateCreated: Date

    public override init() {
        self.phones = []
        self.emails = []
        self.addresses = []
        self.lastModified = .now
        self.dateCreated = .now
        
        super.init()
    }
    
    public init(phone: Phone? = nil, email: Email? = nil, address: Address? = nil) {
        if let phone {
            self.phones = [phone]
        }
        if let email {
            self.emails = [email]
        }
        if let address {
            self.addresses = [address]
        }
        
        self.lastModified = .now
        self.dateCreated = .now
    }

    public init(phones: [Phone] = [], emails: [Email] = [], addresses: [Address] = []) {
        self.phones = phones
        self.emails = emails
        self.addresses = addresses
        self.lastModified = .now
        self.dateCreated = .now
    }
    
    public required init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.phones = try container.decode([Phone].self, forKey: .phones)
        self.emails = try container.decode([Email].self, forKey: .emails)
        self.addresses = try container.decode([Address].self, forKey: .addresses)
        self.lastModified = try container.decode(Date.self, forKey: .lastModified)
        self.dateCreated = try container.decode(Date.self, forKey: .dateCreated)
    }
    
    public func encode(to encoder: any Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.phones, forKey: .phones)
        try container.encode(self.emails, forKey: .emails)
        try container.encode(self.addresses, forKey: .addresses)
        try container.encode(self.lastModified, forKey: .lastModified)
        try container.encode(self.dateCreated, forKey: .dateCreated)
    }
    
    public func hasMatch(for searchText: String) -> Bool {
        addresses.hasMatch(for: searchText)
        || phones.hasMatch(for: searchText)
        || emails.hasMatch(for: searchText)
    }
    
    public func copy() throws -> ContactContainer {
        try JSONDecoder().decode(Self.self, from: try JSONEncoder().encode(self))
    }
}

注:Phone、Address和Email类的Codable协议实现基本一致,copy方法用于更新NSManagedObject的数据。

Core Data模型截图

![Core Data模型属性设置截图]
![Core Data模型Transformer设置截图]


解决方案

问题根源

这个错误的核心是Core Data无法通过Objective-C runtime找到ContactContainer类,新版本系统对Core Data的Objective-C绑定要求更严格,原代码中ContactContainer未显式暴露给Objective-C,导致识别失败。

修复步骤

  1. 给ContactContainer添加Objective-C暴露标记
    修改ContactContainer类定义,添加@objc(ContactContainer),确保Objective-C runtime能识别该类:
@objc(ContactContainer)
public class ContactContainer: NSObject, Codable, ObservableObject {
    // 原有代码保持不变
}
  1. 确保Value Transformer尽早注册
    在App启动的最早期阶段注册Transformer,比如在App结构体的init方法中:
@main
struct YourAppName: App {
    init() {
        ContactValueTransformer.register()
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
  1. 验证Core Data模型设置
    确认模型中:
  • contactContainer属性类型为Transformable
  • Value Transformer选择ContactValueTransformer
  • 自定义类名称为ContactContainer(需与@objc标记的类名完全一致)
  1. 清理重建项目
  • 执行Product > Clean Build Folder
  • 删除设备上的应用
  • 重新编译运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:18:15