当使用来自另一个类实例

时间:2017-12-29 00:43:38

标签: swift swift3 swift4

我有两段代码:

// 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始终为非零。此外,该问题仅在应用程序的发布版本中重现,并且适用于开发构建

1 个答案:

答案 0 :(得分:1)

不是100%肯定,但您可能正在使用Swift inout参数的此功能:

Function Declaration

  

进出参数

     

输入输出参数传递如下:

     
      
  1. 调用该函数时,将复制参数的值。
  2.   
  3. 在功能正文中,副本被修改。
  4.   
  5. 当函数返回时,副本的值将分配给原始参数。
  6.   

请记住此 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值的预期字节序列。

此答案的前半部分适用于您的工作。所以,这不是正确的解决方案。 (你知道一些错误的用法可能会因运气而产生预期的结果。)