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
,它会隐式转换为 NSArray
的 NSNumber
。 the 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 倍。
为什么可以使用 aCoder.encodeObject(myIntArray, forKey: "myKey")
对 Int
的数组进行编码,但在尝试对 UInt8
值的数组进行编码时出现编译器错误?转换实际上并不显着,但我会有 56 个不必要的位来编码...
encodeObject(_:forKey:)
在 NSCoder
中接受 AnyObject?
输入:
func encodeObject(_ objv: AnyObject?, forKey key: String)
因此,如果将 Int
的数组传递给 encodeObject
,它会隐式转换为 NSArray
的 NSNumber
。 the document:
When you bridge from a Swift array to an
NSArray
object, the elements in the Swift array must beAnyObject
compatible. For example, a Swift array of type[Int]
containsInt
structure elements. TheInt
type is not an instance of a class, but because theInt
type bridges to theNSNumber
class, theInt
type isAnyObject
compatible. Therefore, you can bridge a Swift array of type[Int]
to anNSArray
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 倍。