Reputation: 1580
According to the documentation of Data in Swift 3, there is an initializer that I can use to create a Data from UnsafeRawPointer. What I need actually is the opposite. I have a Data, and I want to create a UnsafeRawPointer that points to the bytes of the Data. Here's what I'm doing right now:
1. let data = <from some where>
2. let unsafePointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
3. unsafePointer.initialize(to: 0, count: data.count) // is this necessary?
4. data.copyBytes(to: unsafePointer, count: data.count)
5. let unsafeRawPointer = unsafePointer.deinitialize() // this is of the type UnsafeMutalbleRawPointer, and I can use it where UnsafeRawPointer is needed.
I verified that this code works in Xcode Playground. The code even works without the line number 3. I'm not sure what is the difference with or without the line. Anyway, my question is, am I doing right for what I want? Is there a simpler way to do it?
Upvotes: 27
Views: 32853
Reputation: 539685
withUnsafeBytes()
gives you a (typed) pointer to the bytes,
this can be converted to a raw pointer:
let data = <Data from somewhere>
data.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
let rawPtr = UnsafeRawPointer(u8Ptr)
// ... use `rawPtr` ...
}
The pointer is only valid during the lifetime of the call to the closure.
Alternatively, you can bridge to NSData
and access the raw bytes:
let nsData = data as NSData
let rawPtr = nsData.bytes
Now the pointer is valid in the same scope where nsData
is valid.
As of Swift 5 it is
let data = <Data from somewhere>
data.withUnsafeBytes { rawBufferPointer in
let rawPtr = rawBufferPointer.baseAddress!
// ... use `rawPtr` ...
}
because the closure argument is now a UnsafeRawBufferPointer
.
Upvotes: 58
Reputation: 4760
In Swift 5:
'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
A possible solution is:
buffer.withUnsafeBytes{ (bufferRawBufferPointer) -> Void in
let bufferPointer: UnsafePointer<UInt8> = bufferRawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
let rawPtr = UnsafeRawPointer(bufferPointer)
//USE THE rawPtr
}
Upvotes: 4
Reputation: 47876
Check the latest reference.
We cannot find a method or property which retrieves UnsafeRawPointer
from a Data
.
So, for alternative: func withUnsafeBytes((UnsafePointer) -> ResultType)
You can write something like this:
let data: Data = <initialize it as you like>
data.withUnsafeBytes {(uint8Ptr: UnsafePointer<UInt8>) in
let rawPtr = UnsafeRawPointer(uint8Ptr)
//`rawPtr` (and `uint8Ptr`) is guaranteed to be valid in this closure
//...
//You have no need manage `rawPtr`.
}
(Oh, this is the same as the first half of Martin R's answer.)
But if you want to keep your UnsafeRawPointer
valid for a longer period than in a closure, you need to make a copy of the content of the Data
:
For example:
let uint8Ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
uint8Ptr.initialize(from: data) //<-copying the data
//You need to keep `uint8Ptr` and `data.count` for future management
let uint8PtrCount = data.count
//You can convert it to `UnsafeRawPointer`
let rawPtr = UnsafeRawPointer(uint8Ptr)
//Use `rawPtr` while `uint8Ptr` is valid
//...
//Deinitialize and deallocate the region
uint8Ptr.deinitialize(count: uint8PtrCount)
uint8Ptr.deallocate(capacity: uint8PtrCount)
(You can get UnsafeMutableRawPointer
as a return value of deinitialize(count:)
, but the region is in an uninitialized state, so you should not access the region.)
Upvotes: 9