Swift 3 - Pass struct by reference via UnsafeMutableRawPointer?
Your function copies the data into a local struct, but does not
copy the modified data back. So this would be a possible
solution in your special case:
func testUnsafeMutablePointer(data: UnsafeMutableRawPointer?) {
var testStructInFunc = data!.load(as: TestStruct.self)
testStructInFunc.prop1 = 24
testStructInFunc.prop2 = 1.2
testStructInFunc.prop3 = false
data!.storeBytes(of: testStructInFunc, as: TestStruct.self)
}
But note that this works only if the struct contains only "simple"
values likes integers and floating point values. "Complex" types
like arrays or strings contain opaque pointers to the actual storage
and cannot be simply copied like this.
Another option is to modify the pointed-to struct like this:
func testUnsafeMutablePointer(data: UnsafeMutableRawPointer?) {
let testStructPtr = data!.assumingMemoryBound(to: TestStruct.self)
testStructPtr.pointee.prop1 = 24
testStructPtr.pointee.prop2 = 1.2
testStructPtr.pointee.prop3 = false
}
Both solutions assume that the struct still exists when the callback
is called, since passing a pointer around does not ensure the
lifetime of the pointed-to struct.
As an alternative, consider to use an instance of a class
instead.
Passing retained or unretained pointers to the instance allows to control
the lifetime of the object while the callback is "active", compare
How to cast self to UnsafeMutablePointer<Void> type in swift.
EXC_BAD_ACCESS when trying to pass and read UnsafeMutableRawPointer through VTDecompressionSessionDecodeFrame
Ended up getting this working by using the following:
Input to VTDecompressionSessionDecodeFrame
's frameRefCon
:
let nsString = NSString(string: "Anything")
let frameRefCon = Unmanaged.passRetained(nsString).toOpaque()
Making sure to pass frameRefCon
and not &frameRefCon
On the output callback which has a param of sourceFrameRefCon: UnsafeMutableRawPointer?
:
if let sourceFrameRefCon = sourceFrameRefCon {
let nsString = Unmanaged<NSString>.fromOpaque(sourceFrameRefCon).takeRetainedValue()
print(nsString)
}
Cast a Swift struct to UnsafeMutablePointerVoid
As far as I know, the shortest way is:
var myStruct = TheStruct()
var address = withUnsafeMutablePointer(&myStruct) {UnsafeMutablePointer<Void>($0)}
But, why you need this? If you want pass it as a parameter, you can (and should):
func foo(arg:UnsafeMutablePointer<Void>) {
//...
}
var myStruct = TheStruct()
foo(&myStruct)
Swift Struct Warning Initialization of 'UnsafeMutableRawPointer' results in a dangling pointer
Use withUnsafeMutableBytes
func foo() {
var parameters = MyParameters(position: .zero, size: 0)
withUnsafeMutableBytes(of: ¶meters) { pointer in
// here the lifetime is known
}
}
Understanding UnsafeMutablePointers and how to deal with them
The main use of a pointer in Swift is working with C API and such. For the most part you should use reference semantics instead of pointers in Swift. That means using a class
, when you pass a class
instance around it automatically passes a reference instead of making a copy. Thus, it saves resources and any changes you make to a reference to the instance are reflected everywhere it is referenced. A Swift class is generally instantiated on the heap.
When you convert Objective-C to Swift pointers to objects are generally treated as references to those objects. Internally, a Swift reference is pretty much semantic sugar for a pointer.
Swift structures, on the other hand, have value semantics. They are generally instantiated on the stack and when you pass them around they are copied rather than passing a reference. The same goes when you mutate them, a new instance is created with the new values and it is swapped for the old instance. There are some tricks done where a struct
will wrap a block of memory and hold a pointer to that memory. Thus a struct
may have some reference semantics internally but try to avoid breaking the expectation of a struct
's value being copied when it's passed around.
Some good reading:
Fundamentals of Callbacks for Swift Developers
Thinking in Swift, Part 3: Struct vs. Class
Lazy Initialization with Swift
I'd read these and take a good, hard look at your architecture before trying to use stuff like UnsafeMutablePointer
. Yes, they are useful in some circumstances but they can be a pain to work with and are not necessary for most pure Swift tasks. Especially in a Swift API!
Convert UnsafeMutableRawPointer to UnsafeMutablePointerT in swift 3
In your case, you'd better use allocate(capacity:)
method.
let grayData = UnsafeMutablePointer<UInt8>.allocate(capacity: width * height)
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
Swift 2 - UnsafeMutablePointerVoid to object
This should work: pass the object pointer as an opaque unmanaged pointer
to the callback:
context.info = UnsafeMutablePointer(Unmanaged.passUnretained(myObject).toOpaque())
SCNetworkReachabilitySetCallback(reachability, callback, &context)
and retrieve in the callback via:
func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
let myObject = Unmanaged<MyObject>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
}
Of course this assumes that some strong reference to the object exists
as long as the callback is installed, so that the object is not
deallocated.
Update: Note that both conversions from object pointer to void pointer
and back can be simplified if you are willing to use "unsafe" functions:
context.info = unsafeAddressOf(myObject)
// ...
myObject = unsafeBitCast(info, MyObject.self)
The generated assembly code is – as far as I can see – identical.
Update 2: See also How to cast self to UnsafeMutablePointer<Void> type in swift for more information
about the "bridging" and some helper functions which can be used here.
Swift 3 update (Xcode 8 beta 6):
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
// ...
func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {
if let info = info {
let myObject = Unmanaged<MyObject>.fromOpaque(info).takeUnretainedValue()
// ...
}
}
UnsafeMutablePointer in AURenderCallback
In Swift 3, initializers cannot be used to convert pointer types. In your case, the type of inRefCon
is UnsafeMutableRawPointer
, so you need to use assumingMemoryBound(to:)
method.
And one more, the address of player
passed to the callback needs to be stable all while the sound is playing, addresses taken from inout arguments (specified by &
prefix) does not fulfil this requirement.
The two things above fixed, your code would be something like this:
import Foundation
import AudioToolbox
let sineFrequency = 880.0
// MARK: User data struct
struct SineWavePlayer {
var outputUnit: AudioUnit? = nil
var startingFrameCount: Double = 0
}
// MARK: Callback function
let SineWaveRenderProc: AURenderCallback = {(inRefCon, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData) -> OSStatus in
var player = inRefCon.assumingMemoryBound(to: SineWavePlayer.self)
var j = player.pointee.startingFrameCount
let cycleLength = 44100 / sineFrequency
for frame in 0..<inNumberFrames {
var buffers = UnsafeMutableAudioBufferListPointer(ioData)
buffers?[0].mData?.assumingMemoryBound(to: Float32.self)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
buffers?[1].mData?.assumingMemoryBound(to: Float32.self)[Int(frame)] = Float32(sin(2 * M_PI * (j / cycleLength)))
j += 1
if j > cycleLength {
j -= cycleLength
}
}
player.pointee.startingFrameCount = j
return noErr
}
// MARK: Utility function
func CheckError(_ error: OSStatus, operation: String) {
guard error != noErr else {
return
}
var result: String = ""
var char = Int(error.bigEndian)
for _ in 0..<4 {
guard isprint(Int32(char&255)) == 1 else {
result = "\(error)"
break
}
result.append(String(describing: UnicodeScalar(char&255)))
char = char/256
}
print("Error: \(operation) (\(result))")
exit(1)
}
func CreateAndConnectOutputUnit(_ playerPtr: UnsafeMutablePointer<SineWavePlayer>) {
// Generate a description that matches the output device (speakers)
var outputcd = AudioComponentDescription(componentType: kAudioUnitType_Output, componentSubType: kAudioUnitSubType_DefaultOutput, componentManufacturer: kAudioUnitManufacturer_Apple, componentFlags: 0, componentFlagsMask: 0)
let comp = AudioComponentFindNext(nil, &outputcd)
if comp == nil {
print("Can't get output unit")
exit(-1)
}
CheckError(AudioComponentInstanceNew(comp!, &playerPtr.pointee.outputUnit),
operation: "Couldn't open component for outputUnit")
// Register the render callback
var input = AURenderCallbackStruct(inputProc: SineWaveRenderProc, inputProcRefCon: playerPtr)
CheckError(AudioUnitSetProperty(playerPtr.pointee.outputUnit!, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, UInt32(MemoryLayout<AURenderCallbackStruct>.size)),
operation: "AudioUnitSetProperty failed")
// Initialize the unit
CheckError(AudioUnitInitialize(playerPtr.pointee.outputUnit!),
operation: "Couldn't initialize output unit")
}
func main() {
let playerPtr = UnsafeMutablePointer<SineWavePlayer>.allocate(capacity: 1)
defer {playerPtr.deallocate(capacity: 1)}
playerPtr.initialize(to: SineWavePlayer())
defer {playerPtr.deinitialize()}
// Set up output unit and callback
CreateAndConnectOutputUnit(playerPtr)
// Start playing
CheckError(AudioOutputUnitStart(playerPtr.pointee.outputUnit!),
operation: "Couldn't start output unit")
// Play for 5 seconds
sleep(5)
// Clean up
AudioOutputUnitStop(playerPtr.pointee.outputUnit!)
AudioUnitUninitialize(playerPtr.pointee.outputUnit!)
AudioComponentInstanceDispose(playerPtr.pointee.outputUnit!)
}
Related Topics
How to Cast [Int8] to [Uint8] in Swift
Non-Modular Headers of Openssl Library When Using Modulemap for Swift Framework
C-Style Uninitialized Pointer Passing in Apple Swift
Differences Between Filtering Realm with Nspredicate and Block
Swiftui Share Sheet Crashes iPad
Swiftui - How to Get Coordinate/Position of Clicked Button
How to Apply a Grace Time Using Rx
Avplayerviewcontroller Black Screen When Swiping on iOS 11
Is .Playground a Swift File? Who Can 'See' It
Delegate Property with Different Type in Swift
Xcode Playgrounds Shared Directory Not Working
Nsinvocationoperation' Is Unavailable in Xcode 6.1
Set Custom Uiview Frame in Uiviewrepresentable Swiftui
Read and Write CSV Files in Swift 3
Swift 2 for Loop Low and High Date Between
Convert String to Staticstring
Infer Closure Return Type from Closure Body When Working with Generics