当前位置: 首页 > 面试题库 >

在swift 5中更新代码以避免使用UnsafeMutableBytes弃用警告时发生错误

巫马昆杰
2023-03-14
问题内容

我已更新到swift 5,并且我使用的依赖项之一不会在swift 5中编译。我已修复它,但现在我在整个文件中收到350多个弃用警告。它们都与此类似:

withUnsafeMutableBytes不推荐使用:withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R改用

这是代码的伪装(基本上只是调用ac库的函数):

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]);

我发现(如该答案所述)解决该问题的方法应该是调用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 <_>’。

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

我看了一下Swift5.0:不赞成使用’withUnsafeBytes’:在发布此问题之前[使用withUnsafeBytes<R>(...),它对我的​​处境没有帮助,因为我没有加载指针而是使用了数据。另外,我确实做了文档中告诉我的内容,但这仍然无济于事。

编辑:更清楚一点,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在这里不使用– Data表示“原始”字节的未类型化集合,但是crypto_generichash_keygen想要一个可变的指向
类型化
内存的指针。不推荐使用的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!

与不同Array,这避免了在传递给C
API之前不必用0预填充结果缓冲区,但是这可能不必担心。但就像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)
)

可能
可以使用withUnsafeBytes并调用bindMemory基础指针,但是我不建议这样做,因为它会更改基础内存的类型,这可能会因为您要切换出该事实而潜在地影响共享该内存的任何其他Swift代码的健全性下面的类型。



 类似资料:
  • 我们有一个Java项目。我们为javac启用了Xlint(启用警告)和Werror(将警告视为错误)标志,以确保我们的代码没有警告。最近我们决定不推荐一个类。问题是在某些情况下,SuppressWarnings(“弃用”)根本不会抑制弃用警告,从而导致生成失败。下面是我遇到的用例列表: > 在其他未弃用的类中导入。 在其他已弃用的类中导入。 家长班。 类型参数。例如 但是,即使没有“抑制”,此选项

  • 问题内容: 我有一个React组件,我想在单击时切换一个CSS类。 所以我有这个: 这个问题是ESLint不断告诉我“ this.refs”已贬值。 我该怎么办?我如何解决它而不使用折旧的代码? 问题答案: 您要引用的Lint规则称为 no-string-refs, 并通过以下方式警告您: 之所以收到此警告,是因为已实现了不赞成使用的使用方式(通过使用字符串)。根据您的React版本,您可以执行以

  • 我想在不更新数据库的情况下使用我的实体的setter。 执行此操作时,它会自动更新数据库并将密码设置为null。我想返回密码为null的对象凭据,而不更新数据库 有人知道怎么做吗?

  • 问题内容: 使用createQuery()。list之后是否可以避免投射警告? 我希望找到一种通过通用参数或方法参数指定目标对象的方法,如下所示: 问题答案: 要记住的最重要的一点是, 警告是由于编译器引起的,而不是hibernate的 -您可以告诉编译器忽略未实现的泛型。通过使用HQL,我们以一种类型安全的方式查询数据,不幸的是,java无法进行验证。 有很多方法可以避开hibernate转换的

  • 问题内容: 我刚刚尝试了一个示例代码表单网络,它显示了如下警告 SimpleConvertImage.java:7:警告:com.sun.org.apache.xerces.internal.impl.dv.util.Base64是内部专有API,可以在以后的发行版com.sun.org.apache.xerces中删除。 internal.impl.dv.util.Base64; ^ Simpl

  • 我有一个使用Gradle构建的Java项目,使用MapStruct代码生成器生成映射代码。我有意启用了弃用警告,因为我想知道如果我最终调用弃用的代码,例如在升级库版本时。 我有一个MapSTRt映射器接口(用注释),其中包含一个映射方法。映射方法 当我编译代码时,我在MapSTRt为映射器接口自动生成的具体类中收到两个弃用警告:一个用于实现弃用的映射方法,一个用于调用自定义映射器方法。 我希望找到