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

SwiftData如何用ValueTransformer存储自定义类型的集合?

SwiftData中复用NSMeasurement转换器处理集合类型

核心结论

不需要为数组、字典等集合类型编写全新的ValueTransformer,可以基于已有的单对象转换器复用逻辑;针对Swift集合是struct的问题,通过桥接Foundation集合类型(NSArray/NSDictionary)即可避开NSCoding兼容性限制。


复用单对象转换器的实现方案

假设你已经实现并注册了NSMeasurementValueTransformer单对象转换器,以下是针对数组和字典的复用实现:

1. 先确认单对象转换器的基础实现(示例)

@objc(NSMeasurementValueTransformer)
class NSMeasurementValueTransformer: ValueTransformer {
    override class func transformedValueClass() -> AnyClass {
        return NSData.self
    }

    override class func allowsReverseTransformation() -> Bool {
        return true
    }

    override func transformedValue(_ value: Any?) -> Any? {
        guard let measurement = value as? NSMeasurement else { return nil }
        return try? NSKeyedArchiver.archivedData(withRootObject: measurement, requiringSecureCoding: false)
    }

    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data else { return nil }
        return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSMeasurement
    }
}

// 注册单对象转换器
ValueTransformer.setValueTransformer(NSMeasurementValueTransformer(), 
                                     forName: NSValueTransformerName(rawValue: "NSMeasurementValueTransformer"))

2. 数组类型转换器(复用单对象逻辑)

利用NSArray的归档能力,自动调用元素的转换器:

@objc(NSMeasurementArrayValueTransformer)
class NSMeasurementArrayValueTransformer: ValueTransformer {
    override class func transformedValueClass() -> AnyClass {
        return NSData.self
    }

    override class func allowsReverseTransformation() -> Bool {
        return true
    }

    override func transformedValue(_ value: Any?) -> Any? {
        guard let measurements = value as? [NSMeasurement] else { return nil }
        // 桥接为NSArray,归档时自动使用元素的转换器
        let nsArray = measurements as NSArray
        return try? NSKeyedArchiver.archivedData(withRootObject: nsArray, requiringSecureCoding: false)
    }

    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data,
              let nsArray = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSArray else { return nil }
        return nsArray.compactMap { $0 as? NSMeasurement }
    }
}

// 注册数组转换器
ValueTransformer.setValueTransformer(NSMeasurementArrayValueTransformer(), 
                                     forName: NSValueTransformerName(rawValue: "NSMeasurementArrayValueTransformer"))

3. 字典类型转换器(复用单对象逻辑)

同样桥接为NSDictionary,自动处理值类型的转换:

@objc(NSMeasurementDictionaryValueTransformer)
class NSMeasurementDictionaryValueTransformer: ValueTransformer {
    override class func transformedValueClass() -> AnyClass {
        return NSData.self
    }

    override class func allowsReverseTransformation() -> Bool {
        return true
    }

    override func transformedValue(_ value: Any?) -> Any? {
        guard let measurementDict = value as? [String: NSMeasurement] else { return nil }
        // 桥接为NSDictionary,归档时自动使用值元素的转换器
        let nsDict = measurementDict as NSDictionary
        return try? NSKeyedArchiver.archivedData(withRootObject: nsDict, requiringSecureCoding: false)
    }

    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let data = value as? Data,
              let nsDict = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSDictionary else { return nil }
        var measurementDict = [String: NSMeasurement]()
        for (key, value) in nsDict {
            if let stringKey = key as? String, let measurement = value as? NSMeasurement {
                measurementDict[stringKey] = measurement
            }
        }
        return measurementDict
    }
}

// 注册字典转换器
ValueTransformer.setValueTransformer(NSMeasurementDictionaryValueTransformer(), 
                                     forName: NSValueTransformerName(rawValue: "NSMeasurementDictionaryValueTransformer"))

SwiftData模型中的使用方式

在模型属性上指定对应的转换器即可:

@Model
class MeasurementRecord {
    @Attribute(.transformable(by: "NSMeasurementValueTransformer"))
    var singleMeasurement: NSMeasurement?

    @Attribute(.transformable(by: "NSMeasurementArrayValueTransformer"))
    var measurementList: [NSMeasurement] = []

    @Attribute(.transformable(by: "NSMeasurementDictionaryValueTransformer"))
    var measurementMap: [String: NSMeasurement] = [:]

    init() {}
}

关键原理说明

  1. 复用逻辑:通过桥接Swift集合到Foundation的NSArray/NSDictionary(类类型,支持NSCoding),归档时会自动调用元素已注册的ValueTransformer,完全复用单对象的编码解码逻辑,避免重复代码。
  2. struct兼容:不需要直接处理Swift集合的struct特性,而是利用Foundation集合的归档能力间接完成转换,绕开NSCoding对class类型的限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:43:09