swift - Swift Playground 中的数据值变化

标签 swift nsdata foundation

在 Playground 中,以下代码使用 UnsafeBufferPointer 初始化数据,如 Apple Foundation Documentation 中所述

let data = Data()
let test = Array(0..<10)
let pointer = UnsafeRawPointer(test).assumingMemoryBound(to: UInt8.self)
data = Data.init(buffer: UnsafeBufferPointer(start: pointer, count: MemoryLayout.size(ofValue: test)))
data[8]

多次运行这个程序会产生不同的数据值[8]。为什么值(value)会改变?

最佳答案

MemoryLayout.size(ofValue: test)相当于MemoryLayout<[Int]>.size (该参数仅用作推断通用占位符类型的一种方式)。它没有给你数组缓冲区的大小,而是给你 Array 的大小。 struct itself,目前大小为 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(_:) 获取数组缓冲区的不可变缓冲区指针 View (如果它不是 native 的,例如包装 NSArray ;必须创建它),以及 Data init(buffer:) 使用给定缓冲区指针中的字节构造一个新实例。

如果希望字节与数组中的元素一一对应,则需要使每个元素的长度为 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)

关于swift - Swift Playground 中的数据值变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45289642/

相关文章:

ios - Xcode 9.1 Swift 4,如果使用 "if#available",则无法使用 NSDocumentTypeDocumentAttribute 进行编译

objective-c - 将一个常量变量从 Objective-C 暴露给 Swift

swift - 将结构(包括字节数组)与 SWIFT 结合使用 - 结构到 NSData 和 NSData 到结构

ios - 如何从磁盘上的视频文件中获取 NSData

objective-c - launchd 终止进程时是否调用了 XPC 中断处理程序?

cocoa - 找出 Foundation 可执行文件中的工作文件夹?

ios - 在 Swift 中获取表格内容的高度

ios - 从 Swift 中的蓝牙读取中提取并转换 NSData 值

objective-c - "-copy"和 "-copyWithZone:"有什么区别?

带 Chromecast 的 Swift 框架 : include of non-modular header inside framework module