macosswift3diskarbitration

Correct syntax to unregister a callback in the DiskArbitration framework


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?


Solution

  • 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)