0

在 plist 中存储 CMTime 和 CMTimeRange 等对象的最“现代”Swift 方法是什么?我尝试了以下方法。字典对象存储在 plist 中。

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

并且,

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

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

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

4

1 回答 1

1

PropertyListEncoder/PropertyListDecoderCodable模型类型一起使用。CMTime并且默认情况下CMTimeRangeCodable符合,因此您需要自己添加符合性。

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)
}
于 2020-09-28T09:23:30.600 回答