Ошибка архивации CMTime с NSKeyedArchiver в swift4.0 в ios9.3
Следующий код archivedTimes() успешно собирается в swift4. И работает нормально на устройстве с установленным ios10.3.
typealias Time = CMTime
typealias Times = [Time]
static let times: Times = Array<Int64>.init(1...9).map({ CMTime.init(value: $0, timescale: 100) })
static func archivedTimes() -> Data {
return archived(times: times)
}
static func archived(times: Times) -> Data {
let values = times.map({ NSValue.init(time: $0) })
return NSKeyedArchiver.archivedData(withRootObject: values) // ERROR here
// -- ideally would instead be:
// return NSKeyedArchiver.archivedData(withRootObject: times)
// -- but probably not compatible with ios 9.3
}
Однако во время работы на устройстве с установленным ios9.3 происходит сбой, говоря:
Завершение работы приложения из-за необработанного исключения "NSInvalidArgumentException", причина: "*** -[NSKeyedArchiver encodeValueOfObjCType:at:]: этот архиватор не может кодировать структуры"
Я предполагаю, что это может быть связано с некоторым конфликтом между новым протоколом Codable и старым протоколом NSCoder. Но я не знаю что!
Обратите внимание, что проблема не имеет ничего общего с массивом. Поскольку архивирование простого CMTime также приводит к такой ошибке. Тем не менее, я опубликовал это так, потому что архивирование массива CMTime - моя цель.
1 ответ
Я верю Codable
протокол доступен только в ios10, поэтому на ios9, CMTime
не реализует Codable
,
Так что для ios9 я пошел с классом-оберткой для CMTime
, который реализует NSCoding
протокол.
Это можно сделать, импортировав AVFoundation
который объявляет как расширение NSValue
и к NSCoder
чтобы закодировать CMTime
,
Итак, я пошел с массивом WrappedTime.init($0)
вместо массива NSValue.init(time: $0)
,
class WrappedTime: NSObject, NSCoding {
enum EncodeKey: String {
case time = "time"
}
let time: CMTime
// ...
func encode(with aCoder: NSCoder) {
aCoder.encode(time, forKey: EncodeKey.time.rawValue)
}
required init?(coder aDecoder: NSCoder) {
time = aDecoder.decodeTime(forKey: EncodeKey.time.rawValue)
}
init(_ time: Time) {
self.time = time
}
}