Использование CFNotificationCallback в Swift или блоков @convention(c) в Swift

Я пытаюсь прослушать уведомления CoreTelephony, используя (теперь приватную) функцию CTTelephonyCenterAddObserver C и блоки обратного вызова CFNotificationCallback.

Мой заголовок моста (для расширения частных функций 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?


person JAL    schedule 19.10.2016    source источник
comment
Он не компилируется, потому что observer является UnsafeMutableRawPointer, а не UnsafeRawPointer.   -  person Martin R    schedule 30.01.2017


Ответы (1)


Предоставление компилятору возможности вывести подпись замыкания отлично работает:

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 не разрешен. Когда компилятору разрешено делать вывод о типе замыкания (из типа переменной, в которой оно хранится), он также может вывести атрибут.

person NobodyNada    schedule 19.10.2016
comment
Ах, так оно и есть, я слишком усложнял вещи. Спасибо! - person JAL; 20.10.2016