2015-03-08 3 views
2

Почему можно кодировать массив из Int с использованием aCoder.encodeObject(myIntArray, forKey: "myKey"), но вы получаете ошибку компилятора при попытке кодирования массива значений UInt8? Конверсия на самом деле не драматична, но я бы 56 ненужных биты для кодирования ...Swift encode UInt8

+2

UInt8 может быть получен из объектива c и не является подклассом кодируемого объекта, если у вас нет тонких ints. Я не вижу проблемы с использованием собственного swift-типа. –

+0

BTW, как вы можете преобразовать его только с 56 бит (7 байт)? Самый короткий путь, насколько я могу придумать, это '.map {Int ($ 0)}', 13 байт. – rintaro

+0

@ rintaro Я не имел в виду массив, но тип UInt8 по сравнению с Int – borchero

ответ

6

encodeObject(_:forKey:) в NSCoder принимаю AnyObject? типа:

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

Так что, если вы передаете массив Int в encodeObject, он неявно преобразуется до NSArray от NSNumber s. Этот механизм объясняется в the document:

Когда мост от Swift массива в NSArray объекта, элементы в Swift массива должны быть совместимы AnyObject. Например, массив Swift типа [Int] содержит элементы структуры Int. Тип Int не является экземпляром класса, а потому, что мосты Int относятся к классу NSNumber, тип Int - AnyObject. Таким образом, вы можете связать массив Swift типа [Int] с объектом NSArray.

С другой стороны UInt8 является неAnyObject совместимы:

Все следующие типы автоматически мостиком 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({ $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 составляет около 7x пространства потребления.

Смежные вопросы