UnsafeRawPointer assumingMemoryBound vs. bindMemory
Allocated memory in Swift can either be:
- Uninitialised raw memory
- Uninitialised memory that's bound to a type
- Initialised memory bound to a type
When you allocate memory with UnsafeMutableRawPointer.allocate(bytes:alignedTo:)
, you get uninitialised raw memory.
When you allocate memory with UnsafeMutablePointer<T>.allocate(capacity:)
, you get uninitialised memory that's bound to the type T
.
bindMemory(to:capacity:)
(re-)binds a pointer's memory to a new type, and gives you back a typed pointer to access it with. It can be called on a pointer to memory in any of the above states; though if the memory is initialised, the new bound type must be layout compatible with the old bound type, and both types should be trivial.Note that this method doesn't perform allocation or initialisation; it merely changes the bound type of the memory.
assumingMemoryBound(to:)
is a method for getting a typed pointer from a raw pointer that you already know points to memory bound to a given type. If the memory is not bound to this type, accessing memory through the typed pointer you get back is undefined behaviour.
One important thing to note here is that memory can only be bound to one type at a given time. You are free to rebind to other types (with the above restriction for initialised memory); however attempting to access memory bound to a given type as an unrelated type violates strict aliasing and is therefore undefined behaviour.
Another thing to note is that related types and layout compatible types are independent concepts:
The type
T
is layout compatible with the typeU
if memory bound to typeU
can be bitwise reinterpreted as having typeT
. Note that this isn't necessarily a bidirectional relationship. For example,Int
is layout compatible with(Int, Int)
if one 'instance' of(Int, Int)
can be reinterpreted as being 2 xInt
. The reverse can't be true though; you can't form an(Int, Int)
value from a singleInt
.Two types are related if you can alias overlapping memory with those types. For example, if you have an
UnsafePointer<T>
and anUnsafePointer<U>
, ifT
andU
are unrelated types, then they cannot point to memory that overlaps with each other.
However, I don't believe Swift has officially defined any rules for these terms yet (I expect this'll come with ABI stability).
So what's different after
bindMemory(to:capacity:)
completes?
Currently, nothing. As Andrew Trick says in the mailing list discussion that Martin linked to:
Binding memory communicates to the compiler that the memory locations are safe for typed access. Nothing happens at runtime--until someone writes a type safety sanitizer. It affects the abstract state of the memory location, independent of the pointer variable used to access that memory. Binding memory returns a typed pointer for convenience and clarity, but there’s nothing special about that particular pointer value.
For further reading on this subject, see the memory model explanation section of SE-0107, as well as this unofficial guide to strict aliasing in Swift.
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
How to get bytes out of an UnsafeMutableRawPointer?
load<T>
reads raw bytes from memory and constructs a value of type T
:
let ptr = ... // Unsafe[Mutable]RawPointer
let i16 = ptr.load(as: UInt16.self)
optionally at a byte offset:
let i16 = ptr.load(fromByteOffset: 4, as: UInt16.self)
There is also assumingMemoryBound()
which converts from a Unsafe[Mutable]RawPointer
to a Unsafe[Mutable]Pointer<T>
, assuming that the pointed-to memory contains a value of type T:
let i16 = ptr.assumingMemoryBound(to: UInt16.self).pointee
For an array of values you can create a "buffer pointer":
let i16bufptr = UnsafeBufferPointer(start: ptr.assumingMemoryBound(to: UInt16.self), count: count)
A buffer pointer might already be sufficient for your purpose, it
is subscriptable and can be enumerated similarly to an array.
If necessary, create an array from the buffer pointer:
let i16array = Array(i16bufptr)
As @Hamish said, more information and details can be found at
- SE-0107 UnsafeRawPointer API
Cannot invoke initializer for type UnsafePointer _ with an argument list of type (UnsafeMutableRawPointer)
Please check the official reference when some sort of spec changes has affected with your code. In your case AudioBuffer.mData
is of type UnsafeMutableRawPointer?
, and you need to pass it to the first argument of OutputStream.write(_:maxLength:)
of type UnsafePointer<UInt8>
.
UnsafeMutableRawPointer
You can find this method which returns UnsafeMutablePointer<T>
:
func assumingMemoryBound<T>(to: T.Type)
The concept of bound is sort of confusing, but seems you can use it for pointer type conversion:
outputStreme?.write(buffer.mData!.assumingMemoryBound(to: UInt8.self), maxLength: Int(buffer.mDataByteSize))
(Assuming forced-unwrapping !
is safe enough as suggested by your print(buffer.mData!)
.)
Memory bound-ness is not well defined for most APIs which return pointers, and has no effect as for now. There's another type conversion method func bindMemory<T>(to: T.Type, capacity: Int)
, and both work without problems (again, as for now).
MDQueryGetResultAtIndex and UnsafeRawPointer in Swift 3
The problem in your code
if let item = MDQueryGetResultAtIndex(q, 0) {
let ptr = item.bindMemory(to: MDItem.self, capacity: 1)
let path = MDItemCopyAttribute(ptr.pointee, kMDItemPath)
}
is that the UnsafeRawPointer
is interpreted as a pointer to anMDItem
reference and then dereferenced in ptr.pointee
, but
the raw pointer is the MDItem
reference, so it is dereferenced
once too often.
The "shortest" method to convert the raw pointer to an MDItem
reference
is unsafeBitCast
:
let item = unsafeBitCast(rawPtr, to: MDItem.self)
which is the direct analogue of an (Objective-)C cast.
You can also use the Unmanaged
methods
to convert the raw pointer to an unmanaged reference and from there
to a managed reference (compare How to cast self to UnsafeMutablePointer<Void> type in swift):
let item = Unmanaged<MDItem>.fromOpaque(rawPtr).takeUnretainedValue()
This looks a bit more complicated but perhaps expresses the intention
more clearly. The latter approach works also with (+1) retained
references (using takeRetainedValue()
).
Self-contained example:
import CoreServices
let queryString = "kMDItemContentType = com.apple.application-bundle"
if let query = MDQueryCreate(kCFAllocatorDefault, queryString as CFString, nil, nil) {
MDQueryExecute(query, CFOptionFlags(kMDQuerySynchronous.rawValue))
for i in 0..<MDQueryGetResultCount(query) {
if let rawPtr = MDQueryGetResultAtIndex(query, i) {
let item = Unmanaged<MDItem>.fromOpaque(rawPtr).takeUnretainedValue()
if let path = MDItemCopyAttribute(item, kMDItemPath) as? String {
print(path)
}
}
}
}
UnsafePointer no longer works in swift 3
You can try this:
let rawPointer = UnsafeRawPointer(array1)
let pointer = rawPointer.assumingMemoryBound(to: UInt32.self)
let value = pointer.pointee
Raw pointer is a pointer for accessing untype data.
assumingMemoryBound(to:)
can convert from an UnsafeRawPointer
to UnsafePointer<T>
.
Reference :Swift 3.0 Unsafe World
Value of type 'UnsafeMutableRawPointer' has no subscripts Swift 5
You need to assign a type to your mutable pointer. In the current state it is a mutable pointer to anything but you want it to be a mutable pointer to a buffer of UInt8
values.
To do so simply call assumingMemoryBound
on your data:
let data = calloc(bytesPerRow, height)!.assumingMemoryBound(to: UInt8.self)
Swift 5.0: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes R (...)
In Swift 5 the withUnsafeBytes()
method of Data
calls the closure with an (untyped) UnsafeRawBufferPointer
, and you can load()
the value from the raw memory:
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
(compare How to use Data.withUnsafeBytes in a well-defined manner? in the Swift forum). Note that this requires that the memory is aligned on a 4-byte boundary. For alternatives see round trip Swift number types to/from Data.
Note also that as of Swift 4.2 you can create a random 32-bit integer simply using the new Random
API:
let randomId = UInt32.random(in: .min ... .max)
Pointers in Swift
- Is
UnsafePointer <T>
equal toconst T * Pointer
in ? andUnsafeMutablePointer <T>
is equal toT * Pointer
in C?
Well, use a bridging header in a Swift app to see how the C pointers are bridged:
const int *myInt;
int *myOtherInt;
bridges to
var myInt: UnsafePointer<Int32>!
var myOtherInt: UnsafeMutablePointer<Int32>!
- What is the difference between
Unsafe[Mutable]Pointer
andUnsafeRaw[Mutable]Pointer
?
Swift 3 added a UnsafeRawPointer API to replace the Unsafe[Mutable]Pointer<Void>
type. Conversion between pointers of a different type is no longer allowed in Swift. Instead, the API provides interfaces (.assumingMemoryBound(to:)
or .bindMemory(to:capacity:)
) to bind memory to a type.
With regard to question 3, the ampersand means that the variable is inout
. I don't believe you can declare a variable as inout
unless it is being used by a function that directly modifies the underlying memory, but I'll let the experts correct me. Instead, use withUnsafePointer
.
Thanks to Martin's helpful comment, this syntax was never valid in Swift, and there is no safe way to create "free pointers" to Swift variables.
Convert UnsafeMutableRawPointer to UnsafeMutablePointer T in swift 3
In your case, you'd better use allocate(capacity:)
method.
let grayData = UnsafeMutablePointer<UInt8>.allocate(capacity: width * height)
Related Topics
Cannot Invoke 'Join' with an Argument List of Type (String, [String]) in Swift 2.0
Using Non Ns_Enum Objective-C Enum in Swift
Vertically Aligning Text in an Nstextfield Using Swift
How to Find Actual Swiftui API Documentation (And Not Just the Developer Documentation)
How to Use List Type with Codable? (Realmswift)
Why Can't You Assign an Optional to a Variable of Type 'Any' Without a Warning
Reading Currently Playing Track in MACos Using Scriptingbridge Not Working
Make a Uibarbuttonitem Disappear Using Swift iOS
How to Create a String from Utf8 in Swift
Rxswift Merge Different Kind of Observables
Why Can't We Use Protocol 'Encodable' as a Type in the Func
Swift - Drawing Text with Drawinrect:Withattributes:
Swift Function with Args... Pass to Another Function with Args
Swift Protocol and Return Types on Global Functions
Is There a Difference Between "Is" and Iskindofclass()