【问题标题】:Data withUnsafeBytes is deprecated不推荐使用带有 UnsafeBytes 的数据
【发布时间】:2021-06-09 15:40:14
【问题描述】:

我从我正在开发的应用程序中获得了此代码。当 BLE 人离开团队时,我继承了这个代码。我不擅长低级的东西和数据的东西。我是 UI/UX 前端人员,现在我确实需要亲自动手。这段代码现在有点旧,并且使用了不推荐使用的代码。我一直试图使警告静音,但没有成功,但我一直以相同的代码或错误结束。

这是生成警告的代码。使用 withUnsafeBytes 时的返回行

extension Data {
    func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
        let length = MemoryLayout<T>.size
        guard self.count >= start + length else {
            return (invalid, start+length)
        }
        return (self.subdata(in: start..<start+length).withUnsafeBytes{ $0.pointee }, start+length)
    }
}

此方法用于将字节数组解码为结构。我从 BLE 服务中获取数据,并将各种变量打包成一个字节数组。

如果有任何一种方法可以解决这个问题或更好的方法来做 id。

【问题讨论】:

标签: swift bluetooth-lowenergy unsafe-pointers unsafe-unretained


【解决方案1】:

此处不推荐使用的 withUnsafeBytes 版本是将底层指针绑定到已知类型 (Data.withUnsafeBytes&lt;R, T&gt;(_ body: (UnsafePointer&lt;T&gt;) throws -&gt; R) rethrows -&gt; R) 的版本。

首选替换是不以这种方式绑定的版本,并返回一个原始缓冲区指针(withUnsafeBytes&lt;R&gt;(_ body: (UnsafeRawBufferPointer) throws -&gt; R) rethrows -&gt; R);幸运的是,在这些之间转换只会改变你从指针中读取的方式:

extension Data {
    func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
        let length = MemoryLayout<T>.size
        guard self.count >= start + length else {
            return (invalid, start + length)
        }
    
        return (self.subdata(in: start ..< start + length).withUnsafeBytes { $0.load(as: T.self) }, start + length)
    }
}

使用UnsafeRawBufferPointer.load(as:),您可以安全地从缓冲区中读取一个普通类型T。 (请注意,此方法不能安全地调用非平凡类型,但该方法的原始版本也是如此。)

如果你想进一步简化一点,你可以避免重复start + length

func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
    let length = MemoryLayout<T>.size
    var value = invalid
    if count >= start + length {
        value = subdata(in: start ..< start + length).withUnsafeBytes { $0.load(as: T.self) }
    }

    return (value, start + length)
}

甚至更短,以牺牲可读性为代价:

func scanValueFromData<T>(start: Int = 0, invalid: T) -> (T, Int) {
    let length = MemoryLayout<T>.size
    let value = count >= start + length ? subdata(in: start ..< start + length).withUnsafeBytes { $0.load(as: T.self) } : invalid
    return (value, start + length)
}

【讨论】:

  • @LeoDabus 是的,但我希望尽可能减少代码更改。我也可以包含一个简化版本。
  • IMO 尺寸检查不应该是该方法的一部分。无需使用内存布局extension Data {func object&lt;T&gt;(at index: Index = 0) -&gt; T {subdata(in: index..&lt;endIndex).withUnsafeBytes { $0.load(as: T.self) }}}let uint16Max: UInt16 = Data([255,255,255,255]).object()。 // 65535
  • @LeoDabus 问题在于Data 不够大,无法从中加载值。 Data([]).object() as UInt16 将出现致命错误并显示越界消息。该检查允许您更优雅地默认为另一个值
  • 如果你使用 load(fromByteOffset: start) 而不使用 subdata 方法,你可能会得到一个未对齐的错误。 Swift/UnsafeRawPointer.swift:354:致命错误:从未对齐的原始指针加载
  • 无论如何,你是对的——回到子数据建议,因为它保持兼容性。
猜你喜欢
  • 2018-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
  • 2019-05-13
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
相关资源
最近更新 更多