3

I'm going to implement an observer to be notified when a specific volume disappeared.

The notifications in NSWorkspace are not an option, because I need a notification about device switched off rather than device unmounted.

Registering is pretty easy ( I left out the error handling)

var callbackSession : DASession?

let callbackSession = DASessionCreate(kCFAllocatorDefault)
DASessionSetDispatchQueue(callbackSession!, DispatchQueue.global())  
DARegisterDiskDisappearedCallback(callbackSession!, nil, volumeDidDisappearCallback, nil)

The callback closure is

let volumeDidDisappearCallback : DADiskDisappearedCallback = { (disk, context) in
   // do something with disk
}

The unregister method

func DAUnregisterCallback(_ session: DASession, _ callback: UnsafeMutableRawPointer, _ context: UnsafeMutableRawPointer?)

expects an generic UnsafeMutableRawPointer rather than one of the specific callback types.

When I pass the callback closure to the callback parameter I get

Cannot convert value of type 'DADiskDisappearedCallback' (aka '@convention(c) (DADisk, Optional) -> ()') to expected argument type 'UnsafeMutableRawPointer'

My question is: How can I convert the callback object volumeDidDisappearCallback to UnsafeMutableRawPointer?

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Does passing `unsafeBitCast(volumeDidDisappearCallback, to: UnsafeMutableRawPointer.self)` to the deregister function work? – Martin R Nov 02 '16 at 21:10
  • @MartinR It works even without unregistering the callback but I want to release the resources correctly. It compiles if I make the closure mutable and pass `&volumeDidDisappearCallback` but is this valid? Your suggestion compiles, too. – vadian Nov 02 '16 at 21:14
  • The callback type is declared as `@convention(c)`, so this is essentially a (C compatible) function pointer. Therefore casting it to a pointer might be the right thing. But I haven't tested it. – Martin R Nov 02 '16 at 21:22
  • Thanks, I will test it, too. I'm just porting an ObjC project to Swift and got stuck at this issue. – vadian Nov 02 '16 at 21:27

1 Answers1

3

DADiskDisappearedCallback is defined as

public typealias DADiskDisappearedCallback = @convention(c) (DADisk, UnsafeMutableRawPointer?) -> Swift.Void

which is the Swift mapping of the C function pointer

typedef void (*DADiskAppearedCallback)(DADiskRef disk, void *context);

The unregister function is defined in C as

void DAUnregisterCallback(DASessionRef session, void *callback, void *context);

with a void *callback parameter, and in C you can pass the various kinds of callback function pointers (DADiskAppearedCallback, DADiskDescriptionChangedCallback, ...) without casting.

In Swift you have to cast the function pointer to a void pointer explicitly:

let cb = unsafeBitCast(volumeDidDisappearCallback, to: UnsafeMutableRawPointer.self)
DAUnregisterCallback(callbackSession!, cb, nil)
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382