Xcode tells me:
'withUnsafeBytes' is deprecated: use
withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
instead
But I cannot figure out, how to use this correctly.
Any Help?
Current code:
let bigNum: UInt64 = data.withUnsafeBytes
{ (pointer: UnsafePointer) -> UInt64 in
return pointer.pointee
Works, but creates warning.
Gerriet.
It looks like
you're not the only one who's run into issues with
UnsafeRawBufferPointer
(h/t
@mjtsai
). I'm not terribly familiar with the API so I don't know how safe the following code is, but at least it compiles:
let bigNum: UInt64 = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> UInt64 in
return bytes.load(as: UInt64.self)
You could write this more concisely as follows:
let bigNum: UInt64 = data.withUnsafeBytes { bytes in
return bytes.load(as: UInt64.self)
Or you could even make it a one-liner:
let bigNum = data.withUnsafeBytes { $0.load(as: UInt64.self) }
let bigNum = data.withUnsafeBytes { $0.load(as: UInt64.self) }
That's safe if data is 8-byte aligned. And it's currently the best way to do it IMO. In the past I've suggested adding Data APIs to bypass the unsafe closure-based API, like this, but we're not there yet:
e.g. let bigNum = data.load(as: UInt64.self) }
We also don't have an API for loading unaligned data, so if alignment can't be guaranteed you still have to do something like this:
var bigNum = Int64(0)
withUnsafeMutableBytes(of: &bigNum) {
data.copyBytes(to: $0, from: 0..<MemoryLayout<Int64>.size)
...and it just took me a long time to figure out the right incantation for that.
Thanks for clearing this up!
One additional question: would
let subdata = data.subdata(in: 3 ..< 3 + 8)
be 8-byte aligned?
But I find this all very confusing.
I really would like to write:
let bigNum = UInt64(data: data)
let bigNum = UInt64(data: data, offset: 7)
and would expect nil (if data is too short) or a value.
Even better (as I am receiving data in network byte order) would be:
let bigNum = UInt64(data: data, endianness: .bigEndian) // converts from bigEndian to host endianness
I am sure the compiler could figure this out.
Gerriet.
var bigNum = Int64(0)
withUnsafeMutableBytes(of: &bigNum) {
data.copyBytes(to: $0, from: 0..<MemoryLayout<Int64>.size)
Unless I am mistaken, this can be shortened to
var bigNum = Int64(0)
withUnsafeMutableBytes(of: &bigNum) {
data.copyBytes(to: $0)
since copyBytes()
limits the number of bytes to copy to the size of the target buffer.
I filed a new JIRA for this, [SR-10778] Foundation Data should have an API for reading/writing arbitrary trivial types (without exposing unsafe pointers) · Issue #3329 · apple/swift-corelibs-foundation · GitHub, based on an old radar rdar://problem/28201395 Add Foundation Data API for moving typed values into and out of raw bytes. /cc @Philippe_Hausler, @itaiferber I would be nice to have this soon so people aren't always forced to understand how to work with unsafe pointers.
Gerriet_M_Denkmann1:
One additional question: would
let subdata = data.subdata(in: 3 ..< 3 + 8)
be 8-byte aligned?
No, unless data
happened to be misaligned to begin with.
I really would like to write:
let bigNum = UInt64(data: data)
let bigNum = UInt64(data: data, offset: 7)
and would expect nil (if data is too short) or a value.
I suppose extensions could be provided for the scalar types. I don't think it can replace a generic copyBytes
API. Note that Data APIs use indices instead of byte offsets. I also think it's more conventional for Swift libraries to trap on something the user would normally check for themselves rather than force the user to unwrap an optional.
Even better (as I am receiving data in network byte order) would be:
let bigNum = UInt64(data: data, endianness: .bigEndian) // converts from bigEndian to host endianness
I think the conventional way to do it is
UInt64(data: data).bigEndian
Actually, I agree with your original suggestion. I added a note about this to the JIRA bug.
I have the same warning in my function and really don't know how to fix it. Anyone have any idea ?
func writeData(_ data: Data) {
_ = data.withUnsafeBytes { // warning here
self.write($0, maxLength: data.count)
The use of write(_:maxLength:)
makes me suspect you have an extension on OutputStream
. If so, see this DevForums thread.
Share and Enjoy
Quinn “The Eskimo!” @ DTS @ Apple
_ = data.withUnsafeBytes {
write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count)