问题描述
在plist中存储诸如CMTime和CMTimeRange之类的对象的最“现代” Swift方法是什么?我尝试了以下方法。字典对象将存储在plist中。
dictionary["timeRange"] = NSValue(timeRange: timeRange)
还有
dictionary["timeRange"] = CMTimeRangeCopyAsDictionary(timeRange,allocator: kCFAllocatorDefault)
有人指出,第一种方法的问题是NSValue更像是Objective-C的东西,需要对其进行存档,然后才能将其存储在plist中。第二种方法是基于字典的方法,其中timeRange存储为CFDictionary,但与plist兼容,无需存档。但是CFDictionary离Swift更远了!
那么使CMTimeRange属性列表可序列化的现代方法是什么?
解决方法
将PropertyListEncoder
/ PropertyListDecoder
与Codable
模型类型一起使用。 CMTime
和CMTimeRange
在默认情况下不符合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)
}