Swift 3 - Pass Struct by Reference via Unsafemutablerawpointer

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



Leave a reply



Submit