Using CFNotificationCallback in Swift, or, @convention(c) blocks in Swift

I am trying to listen to CoreTelephony notifications using the (now private) CTTelephonyCenterAddObserver C function and CFNotificationCallback callback blocks.

My bridging header (to extern the private C functions):

  • Qt: How to create a .mp4 from a collection of QOpenGLFramebufferObjects or QImages or Glunit textures
  • malloc: *** error: incorrect checksum for freed object - object was probably modified after being freed
  • Viewing a dynamically-allocated array with the Xcode debugger?
  • SDL Error Undefined symbols for architecture x86_64 “_SDL_main”
  • Setup Xcode and FLTK
  • Apple Instruments has mangled symbols and greyed out symbol names when profiling C++ application
  • #include <CoreFoundation/CoreFoundation.h>
    
    #if __cplusplus
    extern "C" {
    #endif
    
    #pragma mark - API
    
        /* This API is a mimic of CFNotificationCenter. */
    
        CFNotificationCenterRef CTTelephonyCenterGetDefault();
        void CTTelephonyCenterAddObserver(CFNotificationCenterRef center, const void *observer, CFNotificationCallback callBack, CFStringRef name, const void *object, CFNotificationSuspensionBehavior suspensionBehavior);
        void CTTelephonyCenterRemoveObserver(CFNotificationCenterRef center, const void *observer, CFStringRef name, const void *object);
        void CTTelephonyCenterRemoveEveryObserver(CFNotificationCenterRef center, const void *observer);
    
        void CTIndicatorsGetSignalStrength(long int *raw, long int *graded, long int *bars);
    
    #pragma mark - Definitions
    
        /* For use with the CoreTelephony notification system. */
        extern CFStringRef kCTIndicatorsSignalStrengthNotification;
    
    #if __cplusplus
    }
    #endif
    

    My Swift code:

    let callback: CFNotificationCallback = { (center: CFNotificationCenter?, observer: UnsafeRawPointer?, name: CFString?, object: UnsafeRawPointer?, info: CFDictionary?) -> Void in
        // ...
    }
    
    CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault().takeUnretainedValue(), nil, callback, kCTIndicatorsSignalStrengthNotification.takeUnretainedValue(), nil, .coalesce)
    

    However, I can’t get the signature of my completion variable to match the requirements of the CFNotificationCallback typealias.

    Cannot convert value of type
    '(CFNotificationCenter?, UnsafeRawPointer?, CFString?, UnsafeRawPointer?, CFDictionary?) -> Void'
    to specified type
    'CFNotificationCallback' (aka '@convention(c) (Optional<CFNotificationCenter>, Optional<UnsafeMutableRawPointer>, Optional<CFNotificationName>, Optional<UnsafeRawPointer>, Optional<CFDictionary>) -> ()')
    

    How can I get @convention(c) closures to play nicely in Swift?

    Solutions Collect From Internet About “Using CFNotificationCallback in Swift, or, @convention(c) blocks in Swift”

    Letting the compiler infer the closure’s signature works fine:

    let callback: CFNotificationCallback = { center, observer, name, object, info in
        //works fine
    }
    

    Trying to specify @convention(c) in the closure’s declaration gives an error:

    let callback: CFNotificationCallback = { @convention(c) (center: CFNotificationCenter?, observer: UnsafeRawPointer?, name: CFString?, object: UnsafeRawPointer?, info: CFDictionary?) -> Void in
        //Attribute can only be applied to types, not declarations.
    }
    

    It seems like what’s going on is that when you manually declare the closure’s type, it forces the compiler to use that exact type. But that’s technically a closure declaration and not a type declaration, so the @convention attribute isn’t allowed. When the compiler is allowed to infer the closure’s type (from the type of the variable it is being stored in), it can infer the attribute too.