我使用[Uint8]
数组做了很多工作。但我经常需要将这些对象重新设置为NSData
对象以与CoreBluetooth
等iOS框架进行交互。所以我有很多代码可能看起来像:
var input:[UInt8] = [0x60, 0x0D, 0xF0, 0x0D]
let data = NSData(bytes: input, length: input.count)
厌倦了必须插入这个额外的let data = ...
行,我想我只是扩展那些带有计算属性的数组来完成工作。然后我可以做以下事情:
aBluetoothPeriperal.write(myBytes.nsdata, ...)
所以它基本上只是延长糖。我无法扩展Array,但我可以扩展协议:
extension SequenceType where Generator.Element == UInt8 {
var nsdata:NSData {
return NSData(bytes: self, length: self.count)
}
}
会产生如下错误:
Playground execution failed: MyPlayground.playground:3:24: error: cannot convert value of type 'Self' to expected argument type 'UnsafePointer<Void>' (aka 'UnsafePointer<()>')
return NSData(bytes: self, length: self.count)
^~~~
可悲的是,我使用Swift的次数越来越多 - 而且我确实喜欢Swift的一些东西 - 我越是想起我在尝试理解大量无用的编译器输出时的负面体验几年前C ++有很多泛型和东西。请Obi Wan,帮我看看这里的光!
答案 0 :(得分:3)
NSData(bytes:, length:)
将UnsafePointer<Void>
作为第一个参数,您无法在此处传递任意SequenceType
。
你可以传递一个Array
,它将作为地址传递
第一个数组元素。但是不能保证Array
元素
存储在连续的内存中。
因此:
Array
扩展名,而不是Sequence
扩展名。withUnsafeBufferPointer()
方法获取指针
到连续的阵列存储。可能的解决方案:
extension Array where Element : IntegerType {
var nsdata : NSData {
return self.withUnsafeBufferPointer {
NSData(bytes: $0.baseAddress, length: self.count * strideof(Element))
}
}
}
let input:[UInt8] = [0x60, 0x0D, 0xF0, 0x0D]
print(input.nsdata) // <600df00d>
Swift目前不允许限制数组扩展 具体类型:
extension Array where Element == UInt8 { }
// error: same-type requirement makes generic parameter 'Element' non-generic
因此它被推广到符合IntegerType
的任何元素。
对于序列,您可以先转换为数组:
let data = Array(myUInt8sequence).nsdata
答案 1 :(得分:1)
这似乎做你想要的。
protocol ByteOnly: IntegerType {}
extension UInt8: ByteOnly {}
extension Array where Element: ByteOnly {
var n : NSData { return NSData(bytes: self, length: self.count) }
}
// does it work with UInt8
var input5:[UInt8] = [0x61, 0x0D, 0xF1, 0x0D]
let data5 = input5.n // YES
// does it work on ints?
var ints: [Int] = [3,4,5,6,7,8]
let idata5 = ints.n // no