如何抽象不同的字节缓冲区类型? (NSData,[UInt8],...)

时间:2016-02-07 09:22:09

标签: swift

在Swift中有不同的方法来访问字节缓冲区,最常见的可能是UnsafeBufferPointer<UInt8>,而实际存储可以在NSData[UInt8],{{1或其他。

如果我正在编写库代码,我希望它尽可能通用并适应用户对字节缓冲区的选择,同时仍然尽可能方便地使用它。我目前的代码如下:

ContiguousArray<UInt8>

这是一个简单的解决方案,但它有点重复。 我想到了一个更通用的解决方案:

import Foundation

func stringFromUTF8Bytes(bytes: UnsafeBufferPointer<UInt8>) throws -> String {
    if let s = String(bytes: bytes, encoding: NSUTF8StringEncoding) {
        return s
    } else {
        throw Error.StringEncodingFailure
    }
}

func stringFromUTF8Bytes(bytes: ContiguousArray<UInt8>) throws -> String {
    return try bytes.withUnsafeBufferPointer(stringFromUTF8Bytes)
}

func stringFromUTF8Bytes(bytes: [UInt8]) throws -> String {
    return try bytes.withUnsafeBufferPointer(stringFromUTF8Bytes)
}

func stringFromUTF8Bytes(data: NSData) throws -> String {
    return try data.withUnsafeBufferPointer(stringFromUTF8Bytes)
}

enum Error: ErrorType {
    case StringEncodingFailure
}

现在,我可以轻松地为protocol BufferType { func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R } func stringFromUTF8BytesGeneric(bytes: BufferType) throws -> String { return try bytes.withUnsafeBufferPointer { ptr in if let s = String(bytes: ptr, encoding: NSUTF8StringEncoding) { return s } else { throw Error.StringEncodingFailure } } }

实施此协议
NSData

但是我找不到一种方法来为泛型类型实现这个协议,例如extension NSData: BufferType { func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R { let bytesBufferPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(bytes), count: length) return try body(bytesBufferPointer) } }

[UInt8]

我的问题:

  • 有没有办法实施// error: constrained extension must be declared on the unspecialized generic type 'Array' with constraints specified by a 'where' clause extension Array<UInt8>: BufferType { } // error: same-type requirement makes generic parameter 'Element' non-generic extension Array: BufferType where Element == UInt8 { } 协议,例如BufferType但不是其他类型,例如[UInt8]

  • 与第一点相比,允许任意数组真的有意义吗?我不这么认为,但也许我错过了什么?

  • 对于我正在尝试做的事情(抽象不同的字节缓冲区类型),我有一个更好的解决方案吗?

1 个答案:

答案 0 :(得分:1)

(好吧,我在输入这个问题的时候确实找到了一个有用的解决方案......所以为了不浪费我的努力,我会发布自己的答案。也许还有其他更好的解决方案。)

您可以制定“通用”[NSWindowController]协议,并且不限制协议实现,而是约束协议的实际用法。这类似于标准库中BufferType的使用方式。

SequenceType

它确实需要为使用protocol BufferType { typealias Element func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R } extension NSData: BufferType { typealias Element = UInt8 func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R { let bytesBufferPointer = UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(bytes), count: length) return try body(bytesBufferPointer) } } extension UnsafeBufferPointer: BufferType { func withUnsafeBufferPointer<R>(@noescape body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R { return try body(self) } } extension Array: BufferType { } extension ContiguousArray: BufferType { } func stringFromUTF8BytesGeneric <BT: BufferType where BT.Element == UInt8> (bytes: BT) throws -> String { switch(bytes.withUnsafeBufferPointer { String(bytes: $0, encoding: NSUTF8StringEncoding) }) { case let .Some(str): return str case .None: throw Error.StringEncodingFailure } } 的每个方法添加泛型约束,否则它会完全按照我的意愿工作:

ByteBuffer