Swift中将NSData转换为[Uint8]

90

我在Swift中找不到解决这个问题的方法(所有解决方法都是使用Objective-C,并且涉及指针,我认为Swift中不存在相同形式的指针)。有没有办法将NSData对象转换为以[Uint8]形式呈现的字节数组?

7个回答

127

如果您以稍微复杂的方式通过指针或通过Swift 3中引入的新Array构造函数遍历数组,则可以避免最初将数组初始化为占位符值:

Swift 3

let data = "foo".data(using: .utf8)!

// new constructor:
let array = [UInt8](data)

// …or old style through pointers:
let array = data.withUnsafeBytes {
    [UInt8](UnsafeBufferPointer(start: $0, count: data.count))
}

Swift 2

Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length))

2
@califrench 对不起,我没听懂。1)我没有发现任何NSArraybytes访问器也没有返回它。2)如果你指的是可能会在后面出现的错误,那么请记住问题中指定了NSData,而不是NS*类的可能不可用性。 - Arkku
1
很抱歉@Arkku,我有点困惑,刚才我一度认为Array()是依赖于NSArray的,但我现在觉得不是这样的... 问题产生在接下来尝试使用下标访问元素时,因为NSArray无法知道它们包含的元素类型,而Swift的Array可以。 - califrench
1
@Dan 对我来说在Swift 2.2和Swift 3中都可以正常工作。在Swift 3中,前一行是let data : NSData! = "foo".data(using: String.Encoding.utf8) - Arkku
1
@Arkku 最新的Swift编译不通过,我不得不将其更改为:array = data.withUnsafeBytes { bytes in Array( UnsafeBufferPointer(start: bytes, count: data.count) ) }。 - Zmey
1
@LeoDabus,这基本上是另一种说法[UInt8](data),自最新编辑以来已经包含在答案中了。(而且我认为这是更清晰的语法,具有显式类型。) - Arkku
显示剩余5条评论

78

Swift 5 解决方案

将数据转换为 [字节]

extension Data {
    var bytes: [UInt8] {
        return [UInt8](self)
    }
}

[字节] 转换为 数据

extension Array where Element == UInt8 {
    var data: Data {
        return Data(self)
    }
}

1
在Swift 5中,Data(bytes:(self))已被弃用 :'( - vmeyer
1
很棒的答案,优雅至极。 - Woodstock
抱歉如果这是一个愚蠢的问题,但这会产生一份副本,对吧? - Tobi Schweiger
@TobiSchweiger 是的,因为在Swift中,数组始终是值类型,所以数组总是会复制。 - whitneyland

49

很有趣,但有更简单的解决方案。在Swift 3中有效。我今天使用了这个。

data: Data // as function parameter    
let byteArray = [UInt8](data)

就这些了! :)
NSData 很容易桥接到 Data。
更新:(由于 Andrew Koster 的评论)
Swift 4.1,Xcode 9.3.1
刚刚已重新检查 - 所有工作都如预期一样。

if let nsData = NSData(base64Encoded: "VGVzdFN0cmluZw==", options: .ignoreUnknownCharacters) {
let bytes = [UInt8](nsData as Data)
print(bytes, String(bytes: bytes, encoding: .utf8))

输出: [84, 101, 115, 116, 83, 116, 114, 105, 110, 103] Optional("TestString")


1
现在Swift 3已经发布,这应该是被接受的解决方案。 - Chrissi
这很可能会复制您的数据。虽然小的话不是什么大问题,但如果数据量很大,可能会引起很多问题。 - Luke
@AndrewKoster 请看一下我的更新,或者提供详细的解释。 - sVd
看起来现在可以工作了。我不知道编译器是否更改或者你的答案是否更改,但是它可以编译了。 - Andrew Koster
1
@AndrewKoster 是的,你知道:检查答案的编辑历史记录。原始答案没有改变,只是添加了更新。(并且在我的答案中,你发表了同样的评论:它在2016年和现在之间没有被编辑过。)当然,你应该知道是否更新了编译器。然而,考虑到这个答案已经在官方发布中工作了几年,我认为更有可能的是在你之前尝试它时出了其他问题。无论如何,答案不能预测未来,所以我对“不再起作用”进行负评价提出质疑。 - Arkku
也许我把这个粘贴到我的代码中时搞砸了?也许我之后改变了一些东西而没有意识到?我没有记录下每一个细节,这个失败的测试。我尝试了另一种方法,在这里发布了,它起作用了。我投票支持它,因为每个人都说现在/仍然有效。 - Andrew Koster

22

你可以使用NSData的getBytes函数获取字节数组的等价物。

由于您没有提供任何源代码,我将使用已转换为NSData的Swift字符串内容。

var string = "Hello World"
let data : NSData! = string.dataUsingEncoding(NSUTF8StringEncoding)

let count = data.length / sizeof(UInt8)

// create an array of Uint8
var array = [UInt8](count: count, repeatedValue: 0)

// copy bytes into array
data.getBytes(&array, length:count * sizeof(UInt8))

println(array)

Swift 3/4

let count = data.length / MemoryLayout<UInt8>.size

// create an array of Uint8
var byteArray = [UInt8](repeating: 0, count: count)
// copy bytes into array
data.getBytes(&byteArray, length:count)

3
Swift 3中,将sizeof(UInt8)替换为MemoryLayout<UInt8>.size。 - Marek H

7

Swift 3/4

let data = Data(bytes: [0x01, 0x02, 0x03])
let byteArray: [UInt8] = data.map { $0 }

1

将Swift 4和图像数据转换为字节数组。

 func getArrayOfBytesFromImage(imageData:Data) ->[UInt8]{

    let count = imageData.count / MemoryLayout<UInt8>.size
    var byteArray = [UInt8](repeating: 0, count: count)
    imageData.copyBytes(to: &byteArray, count:count)
    return byteArray

}

0

你可以尝试一下

extension Data {
func toByteArray() -> [UInt8]? {
    var byteData = [UInt8](repeating:0, count: self.count)
    self.copyBytes(to: &byteData, count: self.count)
    return byteData
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接