Swift 5.0: 'withUnsafeBytes' está obsoleto: use `withUnsafeBytes<R>(…)



deprecated unsafe-pointers (2)

Eu usei anteriormente este código no Swift 4.2 para gerar um 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 está obsoleto no Swift 5.0. Como posso resolver isso?


Answer #1

No Swift 5, o método withUnsafeBytes() de Data chama o encerramento com um UnsafeRawBufferPointer (não UnsafeRawBufferPointer ) e você pode load() o valor da memória bruta:

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

(compare Como usar Data.withUnsafeBytes de uma maneira bem definida? no fórum Swift). Observe que isso requer que a memória esteja alinhada em um limite de 4 bytes. Para alternativas, consulte tipos de números Swift de ida e volta para / de dados .

Note também que a partir do Swift 4.2 você pode criar um inteiro aleatório de 32 bits simplesmente usando a nova API Random :

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

Answer #2

No Xcode 10.2, Swift 5, usando $0.load(as:) não funcionou para mim, tanto ao ler o ponteiro quanto ao escrever nele.

Em vez disso, usando $0.baseAddress?.assumingMemoryBound(to:) parece funcionar bem.

Exemplo de leitura do buffer do ponteiro (o código não está relacionado à pergunta):

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

Exemplo de gravação no ponteiro do buffer (o código não está relacionado à pergunta):

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
    }
}

O código da pergunta seria parecido com:

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

Nos casos em que o 'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(…) persistindo, parece que o compilador pode ficar confuso quando o encerramento tem apenas uma linha . Fazer o fechamento ter duas ou mais linhas pode remover a ambigüidade.





unsafe-pointers