Swift:无法转换类型&#39; Self&#39;预期参数类型&#39; UnsafePointer <void>&#39;

时间:2016-03-22 15:56:02

标签: swift swift-extensions

我使用[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,帮我看看这里的光!

2 个答案:

答案 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