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

  • “-std=gnu++0x”option for MacOS
  • How to set up Xcode to work with instead of Qt Creator?
  • Need to debug my Web API service that's requested from a client machine - need help, how do I do this?
  • Is there a way to show where LLVM is auto vectorising?
  • How to use the CoreAudio API in Swift
  • Pass and access structures using objective-c
  • #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.