【问题标题】:How to properly use CFNotificationCenterAddObserver in Swift for iOS如何在 Swift for iOS 中正确使用 CFNotificationCenterAddObserver
【发布时间】:2014-10-29 17:31:03
【问题描述】:

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

我还尝试按照this post here 的建议桥接到 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's type '(CFNotificationCenter!, () -> CFunctionPointer<((CFNotificationCenter!, UnsafeMutablePointer<Void>, CFString!, UnsafePointer<Void>, CFDictionary!) -> Void)>, () -> (), CFString, NilLiteralConvertible, CFNotificationSuspensionBehavior)' to type 'StringLiteralConvertible'

【问题讨论】:

  • CFNotificationCenterAddObserver 需要一个 CFunctionPointer,你不能从 Swift 中真正创建它(参见 stackoverflow.com/a/25514748/3300036)。您可以通过执行一些类似于此的 Objective-C 桥接来解决它:stackoverflow.com/a/26139259/3300036
  • 谢谢马克,但为什么它会在 ios 文档中快速声明? developer.apple.com/Library/ios/documentation/CoreFoundation/…
  • 你仍然可以在 Swift 中使用它,你只需要传递一个在 C 或 Objective-C 中定义的函数,而不是一个 Swift 闭包函数。
  • 再次感谢马克。我仍然卡住了,请参阅上面编辑的 Q。
  • 我不确定iosLocked 是什么,但看起来您只是将参数放在错误的位置。这为我编译:CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), nil, LockNotifierCallback.notifierProc(), "com.apple.springboard.lockcomputer", nil, CFNotificationSuspensionBehavior.DeliverImmediately)

标签: ios swift notifications darwin


【解决方案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
}

【讨论】:

  • 如果启用了后台应用刷新,那么,在收到 darwin 通知后,应用是否会从后台唤醒以执行一些代码,就像使用远程通知一样?
  • 按住电源按钮的“YourNotificationName”是什么
【解决方案2】:

我写这个是为了将通知从共享扩展传递到它的父应用程序,当在 iPadOS 中时,两者可以同时处于活动状态。

它们被放置在应用程序和扩展程序共享的库中。 App使用ExtensionListener,Extension使用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)
    }
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-04
  • 2022-10-16
  • 2019-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
相关资源
最近更新 更多