Swift 5.0:不推荐使用'withUnsafeBytes':使用`withUnsafeBytes <r>(...)

时间:2019-03-27 13:28:46

标签: swift deprecated unsafe-pointers

我以前在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中已弃用。我该怎么解决?

4 个答案:

答案 0 :(得分:24)

在Swift 5中,withUnsafeBytes()的{​​{1}}方法使用(无类型的)Data调用闭包,您可以load()从原始内存中获取值:

UnsafeRawBufferPointer

(在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 value = data.withUnsafeBytes { $0.load(as: UInt32.self) }

答案 1 :(得分:7)

在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<R>(…)警告仍然存在的情况下,似乎是the compiler can get confused when the closure has only one line。使闭包具有两行或更多行可能会消除歧义。

答案 2 :(得分:2)

我在尝试找出压缩流教程时遇到了此错误。为了使其正常工作,我添加了将原始缓冲区指针转换为UnsafePointer的步骤

我正在研究的教程中的原始代码。

->其中输入:数据

->其中stream:compression_stream

//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 :(得分:2)

解决此警告的另一种方法是使用 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)
}