Why is it possible to encode an array of Int
using aCoder.encodeObject(myIntArray, forKey: "myKey")
but you get a compiler error when trying to encode an array of UInt8
values? Conversion is actually not dramatic but I would have 56 unnecessary Bits to encode...
encodeObject(_:forKey:)
in NSCoder
accept AnyObject?
type:
func encodeObject(_ objv: AnyObject?, forKey key: String)
So if you pass an array of Int
to encodeObject
, it is implicitly converted to NSArray
of NSNumber
s. This mechanism is explained in 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.
On the other hand UInt8
is not AnyObject
compatible:
All of the following types are automatically bridged to
NSNumber
:
- Int
- UInt
- Float
- Double
- Bool
Thats why you can't pass [UInt8]
to encodeObject(_:forKey:)
. You must convert it manually.
If you are concerned about encoded data size, you should use NSData
or raw bytes array instead of NSArray
. Actually, it depends on which NSCoder
are you using, but for example 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")
}
}
then:
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
is about 7x space consuming.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.