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

筅森魡賤 提交于 2020-03-17 07:03:25

问题


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?


回答1:


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.




回答2:


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.)




回答3:


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

}


来源:https://stackoverflow.com/questions/39671789/in-swift-3-how-do-i-get-unsaferawpointer-from-data

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!