Swift编码UInt8

时间:2015-03-08 20:02:29

标签: arrays swift numbers nscoding

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

1 个答案:

答案 0 :(得分:6)

encodeObject(_:forKey:)中的

NSCoder接受AnyObject?类型:

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

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

中解释了这种机制
  

当您从Swift数组桥接到NSArray对象时, Swift数组中的元素必须AnyObject兼容。例如,类型为[Int]的Swift数组包含Int个结构元素。 Int类型不是类的实例,但由于Int类型与NSNumber类桥接,Int类型与AnyObject类型兼容。因此,您可以将类型为[Int]的Swift数组桥接到NSArray对象。

另一方面,UInt8 AnyObject兼容:

  

以下所有类型都会自动桥接到NSNumber

     
      
  • 内部
  •   
  • UINT
  •   
  •   
  •   
  • 布尔
  •   

这就是为什么你无法将[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({ $0.unsignedCharValue })
    }
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(_array.map({NSNumber(unsignedChar:$0)}), 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大约占用了7倍的空间。