我有两段代码:
// Non-working one
public func put(path: String) -> Int64 {
owner.id += 1
writeBatch.put(path.data(), value: Data(buffer: UnsafeBufferPointer(start: &owner.id, count: 1)))
return owner.id
}
并且
// Working one
public func requestId() -> Int64 {
owner.id += 1
return owner.id
}
public func put(path: String) -> Int64 {
var id = requestId()
writeBatch.put(path.data(), value: Data(buffer: UnsafeBufferPointer(start: &id, count: 1)))
return id
}
这两段代码之间的区别仅在于UnsafeBufferPointer(启动参数)。诀窍是非工作版本引用另一个类实例中的值,而工作版本引用本地参数。
我不明白,为什么在一个世界上这无法发挥作用?我花了一个星期来识别这个错误
提前谢谢!
修改的
忘记提出问题所在。该问题具有以下效果:writeBatch
接收空数据,即它用零填充,而owner.id
始终为非零。此外,该问题仅在应用程序的发布版本中重现,并且适用于开发构建
答案 0 :(得分:1)
不是100%肯定,但您可能正在使用Swift inout
参数的此功能:
进出参数
输入输出参数传递如下:
- 调用该函数时,将复制参数的值。
- 在功能正文中,副本被修改。
- 当函数返回时,副本的值将分配给原始参数。
醇>
请记住此 copy-in copy-out 行为,请再次检查您的代码。
writeBatch.put(path.data(), value: Data(buffer: UnsafeBufferPointer(start: &owner.id, count: 1)))
调用初始值设定项UnsafeBufferPointer.init(start:count:)
时,Swift会创建inout
参数&owner.id
的副本。
然后,Swift使用临时副本的地址调用初始化程序。
完成初始化程序后,Swift可以随时释放副本的区域,但创建的UnsafeBufferPointer
仍保留临时区域的地址,该地址在调用Data.init
时可能不可用
因此Data
的内容可以是任何意外的值,但在您的情况下,它似乎全为零。
为避免出现这种意外结果,您不应将inout
参数传递给指针参数,该参数可能在方法调用后保留。
在您的情况下,一种简单的方法是使用Data
directrly的初始值设定项。
请尝试使用此代码,看看会发生什么:
writeBatch.put(path.data(), value: Data(bytes: &owner.id, count: MemoryLayout<Int64>.size))
初始化程序Data.init(bytes:count:)
在区域释放之前复制临时区域中的内容,因此,它应该保存包含owner.id
值的预期字节序列。
此答案的前半部分适用于您的工作。所以,这不是正确的解决方案。 (你知道一些错误的用法可能会因运气而产生预期的结果。)