Ошибка архивации 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
    }
}
Другие вопросы по тегам