【问题标题】:Swift 5.0: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(...)Swift 5.0:不推荐使用“withUnsafeBytes”:使用 `withUnsafeBytes<R>(...)
【发布时间】:2019-08-18 02:11:34
【问题描述】:

我之前在 Swift 4.2 中使用过这段代码来生成一个 id:

public static func generateId() throws -> UInt32 {
    let data: Data = try random(bytes: 4)
    let value: UInt32 = data.withUnsafeBytes { $0.pointee } // deprecated warning!
    return value // + some other stuff 
}

withUnsafeBytes 在 Swift 5.0 上已弃用。我该如何解决这个问题?

【问题讨论】:

    标签: swift deprecated unsafe-pointers


    【解决方案1】:

    解决此警告的另一种方法是使用 bindMemory(to:)

    var rawKey = Data(count: rawKeyLength)
    let status = rawKey.withUnsafeMutableBytes { rawBytes -> Int32 in
        guard let rawBytes = rawBytes.bindMemory(to: UInt8.self).baseAddress else {
            return Int32(kCCMemoryFailure)
        }
        return CCSymmetricKeyUnwrap(alg, ivBytes, iv.count, keyBytes, key.count, wrappedKeyBytes, wrappedKey.count, rawBytes, &rawKeyLength)
    }
    

    【讨论】:

      【解决方案2】:

      我在尝试制作压缩流教程时遇到此错误。为了让它工作,我添加了一个将原始缓冲区指针转换为 UnsafePointer 的步骤

      我正在编写的教程中的原始代码。

      --> 其中输入:数据

      --> 其中流:压缩流

      //Method that shows the deprecation alert
      return input.withUnsafeBytes { (srcPointer: UnsafePointer<UInt8>) in
      
      //holder
      var output = Data()
      
      //Source and destination buffers
      stream.src_ptr = srcPointer  //UnsafePointer<UInt8>
      stream.src_size = input.count
      … etc. 
      }
      

      带有转换的代码以使上述代码与有效方法一起工作

      return input.withUnsafeBytes { bufferPtr in
      
      //holder
      var output = Data()
      
      //Get the Raw pointer at the initial position of the UnsafeRawBuffer
      let base: UnsafeRawPointer? = bufferPtr.baseAddress
      
      //Unwrap (Can be combined with above, but kept it separate for clarity)
      guard let srcPointer = base else {
         return output
      }
      
      //Bind the memory to the type
      let count = bufferPtr.count
      let typedPointer: UnsafePointer<UInt8> = srcPointer.bindMemory(to: UInt8.self, capacity: count)
      
      // Jump back into the original method
      stream.src_ptr = typedPointer  //UnsafePointer<UInt8>
      }
      

      【讨论】:

        【解决方案3】:

        在 Swift 5 中,DatawithUnsafeBytes() 方法使用(无类型的)UnsafeRawBufferPointer 调用闭包,您可以通过 load() 原始内存中的值:

        let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
        

        (比较 Swift 论坛中的 How to use Data.withUnsafeBytes in a well-defined manner?)。请注意,这要求内存在 4 字节边界上对齐。有关替代方案,请参阅round trip Swift number types to/from Data

        另请注意,从 Swift 4.2 开始,您可以简单地使用新的 Random API 创建一个随机 32 位整数:

        let randomId = UInt32.random(in: .min ... .max)
        

        【讨论】:

        • 你能告诉我如何使用这个:data.withUnsafeBytes { CC_SHA256($0, CC_LONG(data.count), &buffer) } ??
        • @mientus:查看stackoverflow.com/a/25762128/1187415 中的 Swift 5 更新。
        • @MartinR 当有 nil/unreal 然后我得到Thread 1: EXC_BAD_ACCESS (code=1, address=0x20) 我们如何处理它?
        【解决方案4】:

        在 Xcode 10.2、Swift 5 上,使用 $0.load(as:) 对我不起作用,无论是读取指针还是写入指针。

        相反,使用$0.baseAddress?.assumingMemoryBound(to:) 似乎效果很好。

        从指针缓冲区读取的示例(代码与问题无关):

        var reachability: SCNetworkReachability?
        data.withUnsafeBytes { ptr in
            guard let bytes = ptr.baseAddress?.assumingMemoryBound(to: Int8.self) else {
                return
            }
            reachability = SCNetworkReachabilityCreateWithName(nil, bytes)
        }
        

        写入缓冲区指针的示例(代码与问题无关):

        try outputData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) in
            let status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
                                              passphrase,
                                              passphrase.utf8.count,
                                              salt,
                                              salt.utf8.count,
                                              CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1),
                                              rounds,
                                              outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
                                                      kCCKeySizeAES256)
            guard status == kCCSuccess else {
                throw Error.keyDerivationError
            }
        }
        

        问题中的代码如下所示:

        let value = data.withUnsafeBytes { 
            $0.baseAddress?.assumingMemoryBound(to: UInt32.self)
        }
        

        'withUnsafeBytes' is deprecated: use withUnsafeBytes&lt;R&gt;(…) 警告持续存在的情况下,它看起来像the compiler can get confused when the closure has only one line。使闭包有两行或多行可能会消除歧义。

        【讨论】:

        • 我用另一种方式来实现第二个例子。这避免了使用withUnsafeMutableBytes:var derivedKeyData = [UInt8](repeating: 0, count: keyByteCount);let derivationStatus = CCKeyDerivationPBKDF(CCPseudoRandomAlgorithm(kCCPBKDF2),passphrase,passphrase.utf8.count,Array(salt),salt.count,hash,rounds,&amp;derivedKeyData,derivedKeyData.count)
        • 没错,在某些情况下,指向已分配整数数组的指针(间接)工作起来更容易。从 Data 到 UInt8 的数组来回转换也非常简单。
        • 我收到错误:“UnsafePointer<_>”类型的值没有成员“baseAddress”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多