UnsafeMutablePointer UInt8 to [UInt8] without memory copy
As already mentioned in the comments, you can create an UnsafeMutableBufferPointer
from the pointer:
let a = UnsafeMutableBufferPointer(start: p, count: n)
This does not copy the data, which means that you have to ensure that
the pointed-to data is valid as long as a
is used.
Unsafe (mutable) buffer pointers have similar access methods like arrays,
such as subscripting:
for i in 0 ..< a.count {
print(a[i])
}
or enumeration:
for elem in a {
print(elem)
}
You can create a "real" array from the buffer pointer with
let b = Array(a)
but this will copy the data.
Here is a complete example demonstrating the above statements:
func test(_ p : UnsafeMutablePointer<UInt8>, _ n : Int) {
// Mutable buffer pointer from data:
let a = UnsafeMutableBufferPointer(start: p, count: n)
// Array from mutable buffer pointer
let b = Array(a)
// Modify the given data:
p[2] = 17
// Printing elements of a shows the modified data: 1, 2, 17, 4
for elem in a {
print(elem)
}
// Printing b shows the orignal (copied) data: 1, 2, 3, 4
print(b)
}
var bytes : [UInt8] = [ 1, 2, 3, 4 ]
test(&bytes, bytes.count)
How do you convert a UnsafeMutablePointer Void to UInt8?
You have to convert the pointer to the correct type first
(a pointer to UInt8
) and then you can access the memory it points to:
let u8 = UnsafePointer<UInt8>(theUnsafeMutablePointerVar).memory
In Swift 3, a void pointer from C is imported to Swift as UnsafeMutableRawPointer
, and one can read the pointed-to data
with
let u8 = theUnsafeMutablePointerVar.load(as: UInt8.self)
Why can I pass [UInt8] type to the UnsafePointer UInt8 type parameter?
It's just a shortcut.
An unsafe pointer is effectively a C array: what we are pointing at is the first address of a contiguous block of memory. Therefore Swift gives you some nice help for when you have a Swift array from which you want to write to the memory: this Swift array is nothing whatever like a C array, but nevertheless, you can pass a pointer to the Swift array or even the Swift array itself, including an array literal, and Swift will just do the right thing.
UnsafeMutablePointer UInt8 : What's the risk?
UnsafeMutablePointer
is how you represent a C pointer in Swift. It's unsafe because the underlying memory the pointer points to could change at anytime without the Swift pointer knowing. It also has no information about the size of the memory block that it points to (thanks Martin).
If your library requires you to use C types, in this case a pointer to a uint8_t
, then you must use UnsafeMutablePointer
. Otherwise I if you just want to represent an array of numbers I would wrap all of the uint8_t
types in an NSArray
as NSNumber
types (or NSData
if you are pointing to a byte stream) for easier bridging.
You can avoid these risks by dereferencing the pointer (if it is non-nil) and copying the value stored at the pointer to a variable in your Swift application.
How to convert Data to UnsafePointer UInt8 ?
The correct way is to use bindMemory()
:
data.withUnsafeBytes { (unsafeBytes) in
let bytes = unsafeBytes.bindMemory(to: UInt8.self).baseAddress!
do_something(bytes, unsafeBytes.count)
}
assumingMemoryBound()
must only be used if the memory is already bound to the specified type.
Some resources about this topic:
- UnsafeRawPointer Migration Guide
- UnsafeRawPointer API
Release UnsafeMutableBufferPointer UInt8 values
You can solve this by using a class
for the actual implementation.
An example how this can be done is given in
Friday Q&A 2015-04-17: Let's Build Swift.Array:
Destruction can be solved by using a
class
, which providesdeinit
. The
pointer can be destroyed there.class
doesn't have value semantics,
but we can solve this by usingclass
for the implementation of the
struct
, and exposing thestruct
as the external interface to the
array. This looks something like:class ArrayImpl<T> {
var ptr: UnsafeMutablePointer<T>
deinit {
ptr.destroy(...)
ptr.dealloc(...)
}
}
struct Array<T> {
var impl: ArrayImpl<T>
}
You then write methods on
Array
that forward to implementations on
ArrayImpl
, where the real work is done.
Applying this approach to your problem could roughly look like this:
private class DataImpl {
typealias Block = UInt8
var blocks: UnsafeMutableBufferPointer<Block>
init(bytes: UnsafeMutablePointer<Block>, length: Int) {
// copy bytes
let bytesCopy = UnsafeMutablePointer<Block>.alloc(length)
bytesCopy.initializeFrom(bytes, count: length)
// init byte blocks
self.blocks = UnsafeMutableBufferPointer<Block>(start: bytesCopy, count: length)
}
deinit {
print("deinit")
blocks.baseAddress.destroy(blocks.count)
blocks.baseAddress.dealloc(blocks.count)
}
}
struct Data {
typealias Block = UInt8
private var impl : DataImpl
init(bytes: UnsafeMutablePointer<Block>, length: Int) {
impl = DataImpl(bytes: bytes, length: length)
}
}
A simple test shows that this works as expected, the data is released
when the variable goes out of scope:
var bytes : [UInt8] = [1, 2, 3, 4]
do {
let data = Data(bytes: &bytes, length: bytes.count)
}
print("finished")
Output:
deinit
finished
Swift convert [UIn16] to UnsafeMutablePointer UInt16
The withXXXBytes
methods get you raw pointers, but here you want a typed pointer. Use withUnsafeMutableBufferPointer
instead and get the base address:
arrayOfUInt16.withUnsafeMutableBufferPointer { (bufferPointer) in
let mutablePointerOfUInt16 = bufferPointer.baseAddress
// do whatever you want with mutablePointerOfUInt16
// just don't "store or return the pointer for later use." as the documentation says
// because the pointer is only valid within this block
}
What is the correct way in swift to wrap a segment of a UInt8 array as a String?
Here's how you can do try this -
import Foundation
func readString(_ data: inout [UInt8], _ x: inout Int) -> String {
let l = 4
var slice: ArraySlice<UInt8> = data[x..<x+l] // No copy, view into existing Array
x += l
return slice.withUnsafeBytes({ pointer in
// No copy, just making compiler happy (assumption that it is bound to UInt8 is correct
if let bytes = pointer.baseAddress?.assumingMemoryBound(to: UInt8.self) {
return String(
bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes), // No copy
length: slice.count,
encoding: .utf8,
freeWhenDone: false
) ?? ""
} else {
return ""
}
})
}
Test
var a: [UInt8] = [
65, 66, 67, 68,
69, 70, 71, 72
]
var x = 0
let test1 = readString(&a, &x)
print("test1 : \(test1)")
// test1 : ABCD
let test2 = readString(&a, &x)
print("test2 : \(test2)")
// test2 : EFGH
Related Topics
Change What Print(Object) Displays in Swift 2.0
Swift 2.0, Alamofire: Set Cookies in Http Post Request
Create Instance of Class Known at Runtime in Swift
How to Pass Structure by Reference
Swift How to Cast from Int? to String
How to Install Package in Xcode via Swift Package Manager
Mutate Function Parameters in Swift
Hide Tab Bar in View with Push
How to Share Both Image and Text Together in Swift
Swift Tableview Cell Set Accessory Type
How to Set Title of Navigation Bar in Swift
Swift Delegate for a Generic Class
How to Add Caching to Asyncimage
How to Make a Local Module with the Swift Package Manager
How to Avoid Migration in Realmswift
If a Function Returns an Unsafemutablepointer Is It Our Responsibility to Destroy and Dealloc