Jake
Jake

Reputation: 1580

In Swift 3, how do I get UnsafeRawPointer from Data?

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

Answers (3)

Martin R
Martin R

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

Reimond Hill
Reimond Hill

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

OOPer
OOPer

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

Related Questions