我不推荐使用这种方式来改变Data:
data.replaceSubrange(0..<2, with: UnsafeBufferPointer(start: &self.crc, count: 1))
请试试这个:
data.replaceSubrange(0..<2, with: &self.crc, count: 2)
很难解释为什么,但我会尝试...
在 Swift 中,inout 参数以copy-in-copy-out 语义工作。当你写这样的东西时:
aMethod(¶m)
在许多情况下,Swift 通过传递param 的实际地址来优化(即使在-Onone 设置中也可能发生)这些步骤,但没有明确记录。
所以,当inout 参数传递给UnsafeBufferPointer 的初始化器时,UnsafeBufferPointer 接收到的地址可能指向一个临时区域,该临时区域将在初始化器完成后立即释放。
因此,replaceSubrange(_:with:) 可能会将已释放区域中的字节复制到Data。
我相信第一个代码在这种情况下会起作用,因为crc 是结构的属性,但是如果有一个简单且安全的替代方案,您最好避免使用不安全的方法。
Brandon Mantzey 自己的回答的评论。
data.append(UnsafeBufferPointer(start: &self.crcOfRecordData, count: 1))
使用上述含义中的安全。由于上述相同的原因,这不安全。
我会这样写:
data.append(Data(bytes: &self.crcOfRecordData, count: MemoryLayout<UInt16>.size))
(假设crcOfRecordData的类型为UInt16。)
如果您不喜欢创建额外的Data 实例,您可以将其写为:
withUnsafeBytes(of: &self.crcOfRecordData) {urbp in
data.append(urbp.baseAddress!.assumingMemoryBound(to: UInt8.self), count: MemoryLayout<UInt16>.size)
}
这个在注释中没有提到,但是按照上面safe的意思,下面这行不是safe。
let uint32Data = Data(buffer: UnsafeBufferPointer(start: &self.someData, count: 1))
都是一样的原因。
我会这样写:
let uint32Data = Data(bytes: &self.someData, count: MemoryLayout<UInt32>.size)
不过,可观察到的意外行为可能会在某些非常有限的条件下发生,而且概率很小。
只有满足以下两个条件时才会发生这种行为:
Swift 编译器生成非优化的copy-in-copy-out 代码
-
在很窄的时间段之间,由于时间区域被释放,直到append方法(或Data.init)完成整个内容的复制,该区域被修改以备其他用途。
李>
条件 #1 仅在当前 Swift 实现中的有限情况下才会成立。
条件 #2 仅在多线程环境中很少发生。 (不过,Apple 的框架使用了许多隐藏线程,您可以在 Xcode 的调试器中找到。)
事实上,我没有看到任何关于上述不安全案例的问题,我的安全可能有点矫枉过正。
但是替代的安全代码并没有那么复杂,是吗?
在我看来,你最好习惯于使用all-cases-safe代码。