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 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)
}
}
}
}
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
Core Data Appears to Lose Data After Xcode Upgrade
Swift Video to Document Directory
Swift - Nsdate - Remove Part of Date
Swiftui Vertically Misaligned Text
How to Build a Recursive Function in Swift to Return a String
Applescript Email Attachment Not Working in Handler
How to Allow a Generic Collection to Perform Under The Hood Conversion in Swift
How to Make Alamofire Post Request with "Form-Data" Parameters
Can't Dismiss View Controller That's Embedded in a Navigation Controller
How to Set Default Clouse Param in View Method
Compiling for iOS 10.3, But Module 'swiftuicharts' Has a Minimum Deployment Target of iOS 13.0
Optional Protocol Requirements, I Can't Get It to Work
Dynamically Set Properties from Dictionary<String, Any> in Swift
F# Asynchronous Http Request - Parse JSON Response
Generating Random Doable Math Problems Swift
Swift String Indexing Combines "\R\N" as One Char Instead of Two
What's The Correct Number Type for Financial Variables in Swift