更新代码以避免 swift 5 中的 UnsafeMutableBytes 弃用警告时出错

2024-01-12

我已经更新到 swift 5,我使用的依赖项之一无法在 swift 5 中编译。我已经修复了它,但现在我在整个文件中收到了 350 多个弃用警告。它们都类似于:

withUnsafeMutableBytes已弃用:使用withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R instead

这是代码片段(它基本上只是调用 C 库函数):

var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { kPtr in
    flutter_sodium.crypto_generichash_keygen(kPtr)
}

作为参考,上面的 crypto_generichash_keybytes() 仅返回 size_t 和crypto_generichash_keygen的签名是void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]);.

我想通了(如这个答案 https://stackoverflow.com/questions/25761344/how-to-hash-nsstring-with-sha1-in-swift/25762128#25762128指出)解决这个问题的方法应该是调用 kPtr.baseAddress:

var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { kPtr in
    flutter_sodium.crypto_generichash_keygen(kPtr.baseAddress)
}

因为应该使用withUnsafeMutableBytes<ResultType>变体而不是已弃用的withUnsafeMutableBytes<ResultType, ContentType>。但是,这会导致错误

类型“UnsafeMutablePointer<_>”的值没有成员“baseAddress”。

如果我明确指定 resultType 和 kPtr:

var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { (kPtr: UnsafeMutableRawBufferPointer) -> Void in
    flutter_sodium.crypto_generichash_keygen(kPtr.baseAddress)
}

我反而得到

UnsafeMutableRawBufferPointer' 不能转换为 'UnsafeMutablePointer<_>'。

有没有快速的专家可以帮助我找出正确的方法来做到这一点?我知道警告只是警告,但我更喜欢编译时没有警告的代码。

我看了一下Swift 5.0:'withUnsafeBytes' 已弃用:使用 `withUnsafeBytes(...) https://stackoverflow.com/questions/55378409/swift-5-0-withunsafebytes-is-deprecated-use-withunsafebytesr在发布这个问题之前,它对我的​​情况没有帮助,因为我没有加载指针而是使用数据。另外,我已经完全按照文档的要求进行操作,但这仍然没有帮助。

编辑:更清楚一点,350 多个警告中的一些与以下代码相关:Data是在代码中分配的,但是其中一些是我收到的Data来自外部来源。看起来像这样:

let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data

var rx = Data(count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = Data(count: flutter_sodium.crypto_kx_sessionkeybytes())
let ret = rx.withUnsafeMutableBytes { rxPtr in
  tx.withUnsafeMutableBytes { txPtr in
    server_pk.withUnsafeBytes { server_pkPtr in
      server_sk.withUnsafeBytes { server_skPtr in
        client_pk.withUnsafeBytes { client_pkPtr in
          flutter_sodium.crypto_kx_server_session_keys(rxPtr, txPtr, server_pkPtr, server_skPtr, client_pkPtr)
        }
      }
    }
  }
}

并调用相应的方法

SODIUM_EXPORT
int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES],
                                  unsigned char tx[crypto_kx_SESSIONKEYBYTES],
                                  const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES],
                                  const unsigned char client_sk[crypto_kx_SECRETKEYBYTES],
                                  const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES])
            __attribute__ ((warn_unused_result));

(我知道代码并不是真正最佳的 swift,但是在处理 dart 和 swift 之间的互操作性时,这就是 flutter 团队提出的解决方法)。

当我问这个问题时,我试图将其简化为最简单的情况,但该情况有一个特定的答案,与我遇到的总体问题不同。


我不会用Data here – Data然而,表示“原始”字节的无类型集合crypto_generichash_keygen想要一个可变指针typed记忆。原因是UnsafeMutablePointer<T>的变体withUnsafeMutableBytes被弃用的原因是,在无类型内存上提供从根本上来说是错误的抽象。

在 Swift 中获取类型内存缓冲区的最简单方法是使用Array:

var k = [UInt8](repeating: 0, count: crypto_generichash_keybytes())
flutter_sodium.crypto_generichash_keygen(&k)

您始终可以将生成的缓冲区转换为Data事后说Data(k).

另一种选择是使用UnsafeMutableBufferPointer:

let k = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: crypto_generichash_keybytes())
defer {
  k.deallocate()
}
flutter_sodium.crypto_generichash_keygen(k.baseAddress!)
// Now use the buffer `k` – just make sure you finish using it before the end of
// the scope when `deallocate()` gets called!

Unlike Array,这避免了在传递给 C API 之前必须用零预先填充结果缓冲区,但这可能并不重要。但就像Array,你可以将这样的缓冲区变成Data只是说Data(k).


对于您收到的情况Data来自某些外部源的值,并且需要将其作为类型化指针传递给 API,最简单、最安全的选择是在传递它之前将其转换为数组,方法是:Array(someData).

例如:

let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data

var rx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())

flutter_sodium.crypto_kx_server_session_keys(
  &rx, &tx, Array(server_pk), Array(server_sk), Array(client_pk)
)

You probably可以用withUnsafeBytes并打电话bindMemory在底层指针上,但我不鼓励它,因为它改变了底层内存的类型,这可能会微妙地影响共享该内存的任何其他 Swift 代码的健全性,因为您要从它下面切换类型。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

更新代码以避免 swift 5 中的 UnsafeMutableBytes 弃用警告时出错 的相关文章

随机推荐