Errors when update code to avoid deprecation warnings withUnsafeMutableBytes in swift 5
I wouldn't use Data
here – Data
represents an untyped collection of "raw" bytes, however crypto_generichash_keygen
wants a mutable pointer to typed memory. The reason why the UnsafeMutablePointer<T>
variant of withUnsafeMutableBytes
was deprecated is that it's fundamentally the wrong abstraction to be providing on untyped memory.
The simplest way to get a buffer of typed memory in Swift is with an Array
:
var k = [UInt8](repeating: 0, count: crypto_generichash_keybytes())
flutter_sodium.crypto_generichash_keygen(&k)
You can always turn the resulting buffer into a Data
value afterwards by saying Data(k)
.
Another option is to use an UnsafeMutableBufferPointer
:
let k = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: crypto_generichash_keybytes())
defer {
k.deallocate()
}
flutter_sodium.crypto_generichash_keygen(k.baseAddress!)
// Now use the buffer `k` – just make sure you finish using it before the end of
// the scope when `deallocate()` gets called!
Unlike Array
, this avoids having to pre-fill the resulting buffer with zeros before being passed off to the C API, however this likely isn't of concern. But just like Array
, you can turn such a buffer into a Data
by just saying Data(k)
.
For cases where you get handed a Data
value from some external source and need to pass it off to an API as a typed pointer, the simplest and safest option is to just turn it into an array before passing it by saying Array(someData)
.
For example:
let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data
var rx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())
flutter_sodium.crypto_kx_server_session_keys(
&rx, &tx, Array(server_pk), Array(server_sk), Array(client_pk)
)
You probably could use withUnsafeBytes
and call bindMemory
on the underlying pointer, but I would discourage it, as it changes the type of the underlying memory which could subtly impact the soundness of any other Swift code sharing that memory due to the fact that you're switching out the type from under it.
Swift 5.0: 'withUnsafeBytes' is deprecated: use `withUnsafeBytesR(...)
In Swift 5 the withUnsafeBytes()
method of Data
calls the closure with an (untyped) UnsafeRawBufferPointer
, and you can load()
the value from the raw memory:
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
(compare How to use Data.withUnsafeBytes in a well-defined manner? in the Swift forum). Note that this requires that the memory is aligned on a 4-byte boundary. For alternatives see round trip Swift number types to/from Data.
Note also that as of Swift 4.2 you can create a random 32-bit integer simply using the new Random
API:
let randomId = UInt32.random(in: .min ... .max)
withUnsafeMutableBytes' is deprecated xcode warning
As @Enricoza points out, the now-deprecated parameter given to the withUnsafeMutableBytes closure is of type UnsafeMutablePointer
, and the new one is UnsafeMutableRawBufferPointer
. In order to get the UnsafeMutablePointer
or UnsafeMutableRawPointer
that CommonCrypto can accept, then you need to get the .baseAddress
optional property on the *Bytes
objects you get from your closures.
Here's a library that uses the new closure parameters: https://github.com/backslash-f/aescryptable/blob/master/Sources/AESCryptable/AESCryptable.swift
You'll note that the main difference is that it unwraps the baseAddress
es in a guard
clause, throws an error if any fail, then uses those baseAddress
es in place of the old parameters to CommonCrypto functions.
withUnsafeBytes' is deprecated warning when passing void* argument to c function in swift 5
You have to change the closure argument to UnsafeRawBufferPointer
and then take its baseAdress
(which is a UnsafeRawPointer?
, the Swift equivalent of void *
in C):
data.withUnsafeBytes( { (ptr : UnsafeRawBufferPointer) in
let value = readFITfile(ptr.baseAddress)
// ...
})
The Swift compiler can also infer the closure argument type automatically:
data.withUnsafeBytes( { ptr in
let value = readFITfile(ptr.baseAddress)
// ...
})
For more information about this problem, see withUnsafeBytes Data API confusion in the Swift forum.
Convert Data to UInt32 using extension
Try this:
let data = Data([0x01,0x02,0x03,0x04])
extension Data {
var uint32:UInt32 {
return UInt32(littleEndian: self.withUnsafeBytes { bytes in
bytes.load(as: UInt32.self)
})
}
}
print(String(format: "%08X", data.uint32)) //->04030201
The new withUnsafeBytes
passes an UnsafeRawBufferPointer
, which has a useful method load(as:)
.
Related Topics
Ambiguous Use of 'Filter' When Converting Project to Swift 4
Cannot Assign to Value: 'self' Is Immutable
Mapping Swift Combine Future to Another Future
Conversion Between Cgfloat and Nsnumber Without Unnecessary Promotion to Double
Table View Cells Changing Colors When Scrolling Swift
Swift Switch Case Compiler Error
Create a Generic Swift Function to Return an Array of Core Data Entities
Scenekit - Why Scnlight Created Automatically in Scnscene
Check Os Version Using Swift on MAC Os X
Uimarkuptextprintformatter and MAC Catalyst
Protocol Associated Type Typealias Assignment Compile Error
Viewwilllayoutsubviews in Swift
Module Compiled with Swift X.1 Cannot Be Imported in Swift X.0.2
How to Hide The Status Bar Programmatically in iOS 8