Swift 编码 UInt8

Swift encode UInt8

为什么可以使用 aCoder.encodeObject(myIntArray, forKey: "myKey")Int 的数组进行编码,但在尝试对 UInt8 值的数组进行编码时出现编译器错误?转换实际上并不显着,但我会有 56 个不必要的位来编码...

encodeObject(_:forKey:)NSCoder 中接受 AnyObject? 输入:

func encodeObject(_ objv: AnyObject?, forKey key: String)

因此,如果将 Int 的数组传递给 encodeObject,它会隐式转换为 NSArrayNSNumberthe document:

中解释了此机制

When you bridge from a Swift array to an NSArray object, the elements in the Swift array must be AnyObject compatible. For example, a Swift array of type [Int] contains Int structure elements. The Int type is not an instance of a class, but because the Int type bridges to the NSNumber class, the Int type is AnyObject compatible. Therefore, you can bridge a Swift array of type [Int] to an NSArray object.

另一方面,UInt8 AnyObject 兼容:

All of the following types are automatically bridged to NSNumber:

  • Int
  • UInt
  • Float
  • Double
  • Bool

这就是为什么您不能将 [UInt8] 传递给 encodeObject(_:forKey:) 的原因。您必须手动转换它。


如果您担心编码后的数据大小,您应该使用 NSData 或原始字节数组而不是 NSArray。实际上,这取决于您使用的 NSCoder,例如 NSKeyedArchiver:

// NSData
class Foo: NSObject, NSCoding {
    var _array: [UInt8]
    init(array:[UInt8]) {
        _array = array
    }
    required init(coder aDecoder: NSCoder) {
        let arrayData = aDecoder.decodeObjectForKey("array") as NSData
        _array = Array(
            UnsafeBufferPointer(
                start: UnsafePointer<UInt8>(arrayData.bytes),
                count: arrayData.length
            )
        )
    }
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(
            NSData(bytes: _array, length: _array.count),
            forKey: "array"
        )
    }
}

// bytes
class Bar: NSObject, NSCoding {
    var _array: [UInt8]
    init(array:[UInt8]) {
        _array = array
    }
    required init(coder aDecoder: NSCoder) {
        var arrayLength:Int = 0
        var buf = aDecoder.decodeBytesForKey("array", returnedLength: &arrayLength)
        _array = Array(UnsafeBufferPointer(start: buf, count: arrayLength))
    }
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeBytes(_array, length: _array.count, forKey: "array")
    }
}

// NSArray of NSNumber
class Baz: NSObject, NSCoding {
    var _array: [UInt8]
    init(array:[UInt8]) {
        _array = array
    }
    required init(coder aDecoder: NSCoder) {
        _array = (aDecoder.decodeObjectForKey("array") as [NSNumber]).map({ [=11=].unsignedCharValue })
    }
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(_array.map({NSNumber(unsignedChar:[=11=])}), forKey:"array")
    }
}

然后:

let array = [UInt8](0 ..< 255)
let foo = Foo(array: array)
let bar = Bar(array: array)
let baz = Baz(array: array)

let fooData = NSKeyedArchiver.archivedDataWithRootObject(foo)
let barData = NSKeyedArchiver.archivedDataWithRootObject(bar)
let bazData = NSKeyedArchiver.archivedDataWithRootObject(baz)

fooData.length // -> 539
barData.length // -> 534
bazData.length // -> 3,454

let fooCopy = NSKeyedUnarchiver.unarchiveObjectWithData(fooData) as Foo
let barCopy = NSKeyedUnarchiver.unarchiveObjectWithData(barData) as Bar
let bazCopy = NSKeyedUnarchiver.unarchiveObjectWithData(bazData) as Baz

NSArray 大约是 space 的 7 倍。