Как правильно использовать CFNotificationCenterAddObserver в Swift для iOS
Потянув мои волосы, получим CFNotificationCenterAddObserver
для работы в Swift.
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
UnsafePointer<Void>(self),
iosLocked,
"com.apple.springboard.lockcomputer" as CFString,
nil,
CFNotificationSuspensionBehavior.DeliverImmediately)
iOS docs указали его, и я пробовал бесчисленные итерации в обратном вызове и небезопасный указатель без успеха.
Вышеупомянутый вызов функции приводит к этому сообщению об ошибке, которое кажется правильным init:
Cannot invoke 'init' with an argument list of type '(CFNotificationCenter!, $T4, () -> (), CFString, NilLiteralConvertible, CFNotificationSuspensionBehavior)'
Я также попытался подключиться к objc как этот пост здесь, но без успеха.
Вот мой мост:
LockNotifierCallback.h:
#import <Foundation/Foundation.h>
@interface LockNotifierCallback : NSObject
+ (void(*)(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo))notifierProc;
@end
и LockNotifierCallback.m:
#import "LockNotifierCallback.h"
static void lockcompleteChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
NSLog(@"success");
}
@implementation LockNotifierCallback
+ (void(*)(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo))notifierProc {
return lockcompleteChanged;
}
@end
с обновленным вызовом CFNotificationCenterAddObserver следующим образом:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
LockNotifierCallback.notifierProc,
iosLocked,
"com.apple.springboard.lockcomputer" as CFString,
nil,
CFNotificationSuspensionBehavior.DeliverImmediately)
и, конечно, LockNotifierCallback.h находится в моем заголовке Bridging. Ошибка продолжается:
Cannot convert the expression type '(CFNotificationCenter!, () -> CFunctionPointer<((CFNotificationCenter!, UnsafeMutablePointer<Void>, CFString!, UnsafePointer<Void>, CFDictionary!) -> Void)>, () -> (), CFString, NilLiteralConvertible, CFNotificationSuspensionBehavior)' to type 'StringLiteralConvertible'
Ответы
Ответ 1
У меня были некоторые проблемы с DarwinNotifications, вы можете попробовать использовать этот класс-оболочку
просто включите заголовочный файл в свой файл моста. И вы можете использовать его быстро.
DarwinNotificationsManager.h:
#import <Foundation/Foundation.h>
#ifndef DarwinNotifications_h
#define DarwinNotifications_h
@interface DarwinNotificationsManager : NSObject
@property (strong, nonatomic) id someProperty;
+ (instancetype)sharedInstance;
- (void)registerForNotificationName:(NSString *)name callback:(void (^)(void))callback;
- (void)postNotificationWithName:(NSString *)name;
@end
#endif
DarwinNotificationsManager.m:
#import <Foundation/Foundation.h>
#import "DarwinNotificationsManager.h"
@implementation DarwinNotificationsManager {
NSMutableDictionary * handlers;
}
+ (instancetype)sharedInstance {
static id instance = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self) {
handlers = [NSMutableDictionary dictionary];
}
return self;
}
- (void)registerForNotificationName:(NSString *)name callback:(void (^)(void))callback {
handlers[name] = callback;
CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationCenterAddObserver(center, (__bridge const void *)(self), defaultNotificationCallback, (__bridge CFStringRef)name, NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
}
- (void)postNotificationWithName:(NSString *)name {
CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationCenterPostNotification(center, (__bridge CFStringRef)name, NULL, NULL, YES);
}
- (void)notificationCallbackReceivedWithName:(NSString *)name {
void (^callback)(void) = handlers[name];
callback();
}
void defaultNotificationCallback (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
NSLog(@"name: %@", name);
NSLog(@"userinfo: %@", userInfo);
NSString *identifier = (__bridge NSString *)name;
[[DarwinNotificationsManager sharedInstance] notificationCallbackReceivedWithName:identifier];
}
- (void)dealloc {
CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationCenterRemoveEveryObserver(center, (__bridge const void *)(self));
}
@end
В быстром режиме вы можете использовать его следующим образом:
let darwinNotificationCenter = DarwinNotificationsManager.sharedInstance()
darwinNotificationCenter.registerForNotificationName("YourNotificationName"){
//code to execute on notification
}
Ответ 2
Я написал это для того, чтобы передать уведомление от общего расширения для родительского приложения, когда в iPadOS оба могут быть активны одновременно.
Они помещены в библиотеку, совместно используемую как приложением, так и расширением. Приложение использует ExtensionListener, расширение использует ExtensionEvent.
final public class ExtensionListener: NSObject {
// the inter-process NotificationCenter
private let center = CFNotificationCenterGetDarwinNotifyCenter()
private var listenersStarted = false
fileprivate static let notificationName = "com.example.CrossProcessExtensionAction" as CFString
public override init() {
super.init()
// listen for an action in the Share Extension
startListeners()
}
deinit {
// don't listen anymore
stopListeners()
}
// MARK: listening
fileprivate func startListeners() {
if !listenersStarted {
self.listenersStarted = true
CFNotificationCenterAddObserver(center, Unmanaged.passRetained(self).toOpaque(), { (center, observer, name, object, userInfo) in
// send the equivalent internal notification
NotificationCenter.default.post(name: NSNotification.Name.SomeInternalExtensionAction, object: nil)
}, Self.notificationName, nil, .deliverImmediately)
}
}
fileprivate func stopListeners() {
if listenersStarted {
CFNotificationCenterRemoveEveryObserver(center, Unmanaged.passRetained(self).toOpaque())
listenersStarted = false
}
}
}
final public class ExtensionEvent: NSObject {
public static func post() {
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFNotificationName(rawValue: ExtensionListener.notificationName), nil, nil, true)
}
}