MemoryLayout.size(ofValue: test)
等效于MemoryLayout<[Int]>.size
(该参数仅用于推断通用占位符类型)。它不给你数组缓冲区的大小,它给你的尺寸为Array
struct 本身,它的大小目前是1个字(在64位机器上是8个字节),因为元素是间接保存的。
因此,您构造的Data
实例只保存8个字节,因此访问data[8]
会读出界限垃圾;这就是为什么你会得到意想不到的结果。这个越界访问实际上是cause a runtime error in Swift 4(与Xcode 9 beta 4一起提供的版本)。
但是忽略了这一切,用UnsafeRawPointer(test)
开始与是未定义行为,因为它使用指向缓冲区这仅适用于初始化器调用的持续时间。 Swift只保证自动生成的指针参数(例如,当将数组传递给常量指针参数时)在给定函数调用的持续时间内有效(请参阅Swift团队的博客文章Interacting with C Pointers)。
如果你只是想阵列的缓冲区的字节转储到Data
例如,你只是想:
let test = Array(0 ..< 10)
let data = test.withUnsafeBufferPointer(Data.init)
// or let data = test.withUnsafeBufferPointer { Data(buffer: $0) }
print(data as NSData) // bridge to NSData to get a full print-out of bytes
// <00000000 00000000
// 01000000 00000000
// 02000000 00000000
// 03000000 00000000
// 04000000 00000000
// 05000000 00000000
// 06000000 00000000
// 07000000 00000000
// 08000000 00000000
// 09000000 00000000>
print(data[8]) // 1
(64位小端机)
它采用withUnsafeBufferPointer(_:)
到获得一个不变的缓冲区指针视图到阵列上的缓冲(如果它不是天然的,例如包装的NSArray
;它必须被创建的),并Data
的init(buffer:)
构造新的实例与从给定的缓冲器点的字节呃。
如果您希望字节与数组中的元素1:1对应,您需要使每个元素的长度为1个字节。
例如,通过带[UInt8]
:
let test = [UInt8](0 ..< 10)
let data = test.withUnsafeBufferPointer(Data.init)
print(data as NSData) // <00010203 04050607 0809>
print(data[8]) // 8
而且因为你现在的UInt8
序列工作,你其实可以通过使用Data
的sequence of UInt8
initialiser简化初始化咯:
let data = Data(test)
这是确切的代码? 'data'是一个常量,所以你不能在这里重新分配它:'data = Data.init(...)' –
是的,它是确切的代码。在Swift 3之前,原因是因为让我们只提到数据的引用,而不是数据本身。然而,在Swift 3之后,基础类被桥接到Swift结构。所以我不知道它为什么有效,但它仍然有效。 –
@Hamish感谢有关MemoryLayout的信息。我真的不知道预期的行为是什么。理想情况下,代码将对应于数组中的数字(我认为)。我想了解更多关于基础框架的知识,为此,已经为每个基础课程制作了使用API的每个部分的游乐场。我已经把它交给了Data,正在通过初始化程序,到达了这个程序,并且现在处于亏损状态。如果你知道如何/为什么有人会使用这个初始值设定项,或者只是知道UnsafePointer,UnsafeBuffer等的一个很好的指南,我会非常感激。 –