在 Swift 中使用 CFNotificationCallback,或者在 Swift 中使用 @convention(c) 块

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

我正在尝试使用(现在私有的)CTTelephonyCenterAddObserver C 函数和 CFNotificationCallback 回调块来收听 CoreTelephony 通知。

我的桥接 header(外部私有 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

我的Swift代码:

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

CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault().takeUnretainedValue(), nil, callback, kCTIndicatorsSignalStrengthNotification.takeUnretainedValue(), nil, .coalesce)

但是,我的 completion 变量签名无法满足 CFNotificationCallback 类型别名的要求。

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>) -> ()')

如何让 @convention(c) 闭包在 Swift 中正常运行?

让编译器推断闭包的签名工作正常:

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

尝试在闭包的声明中指定 @convention(c) 会出现错误:

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.
}

似乎发生的情况是,当您手动声明闭包的类型时,它会强制编译器使用该确切类型。但这在技术上是闭包声明而不是类型声明,因此 @convention 属性是不允许的。当允许编译器推断闭包的类型(从存储它的变量的类型)时,它也可以推断属性。