How to Get Unsaferawpointer on The Swift Object

How to get UnsafeRawPointer on the swift object?

The & syntax does not mean "the address of" or "pointer to" like in C. In Swift, it is an in-out expression.

These can be used to create implicit pointer conversions as a convenience, and that can seem like C's "pointer to" meaning, but it has very different rules and behaviors. For example, there is no promise that obj even has an address. It may be a tagged pointer. Passing it via an in-out expression may allocate memory and copy the value to make the call possible. Similarly, when passing a "pointer to an array," Swift will actually pass a pointer to a contiguous block of values (which may have been copied to make them contiguous) which is not the same as the actual Array struct.

It is not meaningful to say var pointer = &obj. There is no in-out reference there.

There is no general way to take long-lived pointers to objects in Swift without allocating your own memory (and this is rare). The memory model doesn't promise the kinds of lifetimes you'd need to make that sensible. If your code did compile the way you expect it to, the call to foo(pointer) would still be invalid because there's no promise that obj exists at that point and the pointer could be dangling. (There are no references to obj after the first line, so Swift can and often will destroy it, even though it's still "in scope.")

The foo(&obj) syntax is basically a shorthand for:

withUnsafePointer(to: obj) { foo($0) }

It exists to make it easier to call C functions, but it doesn't mean that Swift pointers are anything like C pointers.

For much more on Swift pointers, see Safely manage pointers in Swift from WWDC 2020.

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

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.

Understanding UnsafeRawPointer in objc_setAssociatedObject

Passing reference to the key: UnsafeRawPointer argument of objc_setAssociatedObject passes the address of the variable storage to that function.

Global variables and static member variables (and only those) are guaranteed to have a fixed address.

In your first version, the second and all subsequent calls to objc_setAssociatedObject with the same key replace a previous association.

In your second version, the address of a local variable is passed as key. That address may or may not be the same on subsequent calls. Note that the contents of the string is irrelevant, the key is just a pointer, i.e. the address of that variable.

If you need to associate a variable number of values with a given object then I would suggest to associate a single NSMutableArray (or NSMutableDictionary) and add the values to that array or dictionary.

How to cast self to UnsafeMutablePointerVoid type in swift

An object pointer (i.e. an instance of a reference type) can be
converted to a UnsafePointer<Void> (the Swift mapping of const void *, UnsafeRawPointer in Swift 3) and back. In Objective-C you would write

void *voidPtr = (__bridge void*)self;
//
MyType *mySelf = (__bridge MyType *)voidPtr;

(See 3.2.4 Bridged casts in the Clang ARC documentation for the precise meaning of these
casts.)

Swift has an Unmanaged type for that purpose.
It is a bit cumbersome to use because it works with COpaquePointer
instead of UnsafePointer<Void>. Here are two helper methods
(named after the Objective-C __bridge cast):

func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
// return unsafeAddressOf(obj) // ***
}

func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
// return unsafeBitCast(ptr, T.self) // ***
}

The "complicated" expression is only necessary to satisfy Swifts
strict type system. In the compiled code this is just a cast
between pointers. (It can be written shorter as indicated in the *** comments
if you are willing to use "unsafe" methods, but the compiled
code is identical.)

Using this helper methods you can pass self to a C function as

 let voidPtr = bridge(self)

(or UnsafeMutablePointer<Void>(bridge(self)) if the C function requires
a mutable pointer), and convert it back to an object pointer – e.g.
in a callback function – as

 let mySelf : MyType = bridge(voidPtr)

No transfer of ownership takes place, so you must ensure that self
exists as long as the void pointer is used.


And for the sake of completeness, the Swift equivalent of __bridge_retained and __bridge_transfer from Objective-C would be

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeTransfer<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeRetainedValue()
}

bridgeRetained() casts the object pointer to a void pointer and
retains the object. bridgeTransfer() converts the
void pointer back to an object pointer and consumes the retain.

An advantage is that the object cannot be deallocated between the
calls because a strong reference is held. The disadvantage is that
the calls must be properly balanced, and that it can easily cause retain
cycles.


Update for Swift 3 (Xcode 8):

func bridge<T : AnyObject>(obj : T) -> UnsafeRawPointer {
return UnsafeRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}

func bridge<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

func bridgeRetained<T : AnyObject>(obj : T) -> UnsafeRawPointer {
return UnsafeRawPointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeTransfer<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}

The relevant changes to "unsafe pointers" are described in

  • SE-0017 Change Unmanaged to use UnsafePointer
  • SE-0107 UnsafeRawPointer API

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 an
MDItem 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)
}
}
}
}

how do I extract data from void UnsafePointer in Swift?

As long as you know what kind data you've got holed up in that unsafe pointer, you can always use the various constructors of each variant to cast between the pointers. Your example is trivial to translate if you bear that in mind:

import AudioToolbox

var timeStamp : MusicTimeStamp = 0
var eventType : MusicEventType = 0
var eventData : UnsafePointer<Void> = nil
var eventDataSize : UInt32 = 0;

MusicEventIteratorGetEventInfo(anIterator, &timeStamp, &eventType, &eventData, &eventDataSize);

switch (eventType){
case kMusicEventType_MIDINoteMessage:
let data = UnsafePointer<MIDINoteMessage>(eventData)
let channel = data.memory.channel
let note = data.memory.note
let velocity = data.memory.velocity
let duration = data.memory.duration

case kMusicEventType_MIDIChannelMessage:
//extract info from eventData assuming it's a MIDIChannelMessage.

//case ..., etc.
}

Casting between different UnsafePointerT in swift

struct UnsafePointer<T> has a constructor

/// Convert from a UnsafePointer of a different type.
///
/// This is a fundamentally unsafe conversion.
init<U>(_ from: UnsafePointer<U>)

which you can use here

doThingsOnRawData(UnsafePointer<UInt8>(data.bytes))

You can even omit the generic type because it is inferred from the context:

doThingsOnRawData(UnsafePointer(data.bytes))

Update for Swift 3: As of Xcode 8 beta 6, you cannot convert
directly between different unsafe pointers anymore.

For data: NSData, data.bytes is a UnsafeRawPointer which can
be converted to UnsafePointer<UInt8> with assumingMemoryBound:

doThingsOnRawData(data.bytes.assumingMemoryBound(to: UInt8.self))

For data: Data it is even simpler:

data.withUnsafeBytes { doThingsOnRawData($0) }

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

Swift convert Data to UnsafeMutablePointerInt8

you have to change UnsafeMutablePointer to UnsafePointer

UnsafePointer

resultData?.withUnsafeBytes {(bytes: UnsafePointer<CChar>)->Void in
//Use `bytes` inside this closure

}

UnsafeMutablePointer

 var data2 = Data(capacity: 1024)
data2.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> Void in
//Use `bytes` inside this closure

})

How to use UnsafeMutableRawPointer to fill an array?

First, let's assume you have a UnsafeRawPointer and a length:

let ptr: UnsafeRawPointer = ...
let length: Int = ...

Now you want to convert that to an [float4]. First, you can convert your UnsafeRawPointer to a typed pointer by binding it to a type:

let float4Ptr = ptr.bindMemory(to: float4.self, capacity: length)

Now you can convert that to a typed buffer pointer:

let float4Buffer = UnsafeBufferPointer(start: float4Ptr, count: length)

And since a buffer is a collection, you can initialize an array with it:

let output = Array(float4Buffer)

For much more on working with UnsafeRawPointer, see SE-0138, SE-0107, and the UnsafeRawPointer Migration Guide.



Related Topics



Leave a reply



Submit