web-dev-qa-db-ja.com

Swift 5.0: 'withUnsafeBytes'は非推奨です: `withUnsafeBytes <R>(...)を使用してください

私は以前にこのコードを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で非推奨になりました。これを解決するにはどうすればよいですか?

38
Baran Emre

Swift 5では、DatawithUnsafeBytes()メソッドは、(型なし)UnsafeRawBufferPointerでクロージャを呼び出し、次のことができます load() 生のメモリからの値:

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

(比較 明確に定義された方法でData.withUnsafeBytesを使用する方法? Swiftフォーラム)。これには、メモリがaligned4バイト境界。代替案については、 往復Swiftデータとの数値型 を参照してください。

Swift 4.2以降では、新しい Random AP​​I を使用して32ビット整数をランダムに作成できることに注意してください。

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

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>(…)警告が続く場合、 クロージャーが1行しかないとコンパイラーが混乱する可能性があります のようです。クロージャを2行以上にすることで、あいまいさがなくなる場合があります。

14
Eneko Alonso

この警告を修正してbindMemory(to:)を使用するもう1つの方法。

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)
}
3
Ramis

圧縮ストリームのチュートリアルを理解しようとしたときに、このエラーが発生しました。それを機能させるために、生のバッファポインタをUnsafePointerに変換するステップを追加しました

私が取り組んでいたチュートリアルの元のコード。

->入力:データ

->ここでストリーム: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>
}
2
Mike Critchley