plist 中 CMTime 和 CMTimeRange 的现代方式使用 Swift

Modern way of CMTime and CMTimeRange in plist using Swift

在 plist 中存储 CMTime 和 CMTimeRange 等对象的最'modern' Swift 方法有哪些?我尝试了以下方法。字典对象存储在 plist 中。

  dictionary["timeRange"] =  NSValue(timeRange: timeRange)

还有,

  dictionary["timeRange"] = CMTimeRangeCopyAsDictionary(timeRange, allocator: kCFAllocatorDefault)

有人指出,第一种方法的问题是 NSValue 更像是 Objective-C 类的东西,它需要先存档,然后才能存储在 plist 中。第二种方法是基于字典的方法,其中 timeRange 存储为 CFDictionary 但与 plist 兼容,无需存档。但离Swift!

更远的是CFDictionary

那么使 CMTimeRange 属性 列表可序列化的现代方法是什么?

PropertyListEncoder/PropertyListDecoderCodable 模型类型一起使用。 CMTimeCMTimeRange 默认不符合 Codable ,所以你需要自己添加一致性。

extension CMTime: Codable {
    enum CodingKeys: String, CodingKey {
        case value
        case timescale
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let value = try container.decode(CMTimeValue.self, forKey: .value)
        let timescale = try container.decode(CMTimeScale.self, forKey: .timescale)
        self.init(value: value, timescale: timescale)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(value, forKey: .value)
        try container.encode(timescale, forKey: .timescale)
    }
}

extension CMTimeRange: Codable {
    enum CodingKeys: String, CodingKey {
        case start
        case duration
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let start = try container.decode(CMTime.self, forKey: .start)
        let duration = try container.decode(CMTime.self, forKey: .duration)
        self.init(start: start, duration: duration)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(start, forKey: .start)
        try container.encode(duration, forKey: .duration)
    }
}

struct Model: Codable {
    let time: CMTime
    let timeRange: CMTimeRange
}

let model = Model(time: CMTime.invalid, timeRange: CMTimeRange(start: CMTime(), end: CMTime()))
do {
    let encodedData = try PropertyListEncoder().encode(model)
    let decodedData = try PropertyListDecoder().decode(Model.self, from: encodedData)
    print(decodedData)
} catch {
    print(error)
}