2014-10-29 15 views
10

Estrarre i miei capelli ottenendo CFNotificationCenterAddObserver per lavorare in Swift.Come utilizzare correttamente CFNotificationCenterAddObserver in Swift per iOS

 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), 
     UnsafePointer<Void>(self), 
     iosLocked, 
     "com.apple.springboard.lockcomputer" as CFString, 
     nil, 
     CFNotificationSuspensionBehavior.DeliverImmediately) 

Il iOS docs hanno elencato e ho cercato innumerevoli iterazioni sul callback e il puntatore non sicuro senza successo.

I suddetti risultati chiamata di funzione in questo messaggio di errore, che sembra essere init corretto:

Cannot invoke 'init' with an argument list of type '(CFNotificationCenter!, $T4,() ->(), CFString, NilLiteralConvertible, CFNotificationSuspensionBehavior)' 

Ho anche provato a colmare objc come suggerisce this post here, ma senza successo.

Ecco il mio ponte:

LockNotifierCallback.h:

#import <Foundation/Foundation.h> 

@interface LockNotifierCallback : NSObject 

+ (void(*)(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo))notifierProc; 

@end 

e 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 

con la chiamata CFNotificationCenterAddObserver aggiornata come segue:

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), 
     LockNotifierCallback.notifierProc, 
     iosLocked, 
     "com.apple.springboard.lockcomputer" as CFString, 
     nil, 
     CFNotificationSuspensionBehavior.DeliverImmediately) 

e ovviamente LockNotifierCallback.h si trova nella mia intestazione Bridging. Errore continua:

Cannot convert the expression's type '(CFNotificationCenter!,() -> CFunctionPointer<((CFNotificationCenter!, UnsafeMutablePointer<Void>, CFString!, UnsafePointer<Void>, CFDictionary!) -> Void)>,() ->(), CFString, NilLiteralConvertible, CFNotificationSuspensionBehavior)' to type 'StringLiteralConvertible' 
+2

'CFNotificationCenterAddObserver' prende un' CFunctionPointer' che non puoi davvero creare da Swift (vedi http://stackoverflow.com/a/25514748/3300036). Puoi aggirare il problema facendo un bridging Objective-C simile a questo: http://stackoverflow.com/a/26139259/3300036 –

+1

Grazie Mark, ma perché sarebbe sotto una rapida dichiarazione nei documenti ios? https://developer.apple.com/Library/ios/documentation/CoreFoundation/Reference/CFNotificationCenterRef/index.html#//apple_ref/c/func/CFNotificationCenterAddObserver – zooster

+1

Puoi ancora usarlo da Swift, devi solo passarlo una funzione definita in C o Objective-C e non una funzione Swift di chiusura. –

risposta

9

ho avuto alcuni problemi con DarwinNotifications, si può provare a utilizzare questa classe wrapper sufficiente includere file di intestazione nel file colmare. E puoi usarlo in fretta.

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 

In rapida è possibile utilizzare in questo modo:

let darwinNotificationCenter = DarwinNotificationsManager.sharedInstance() 
darwinNotificationCenter.registerForNotificationName("YourNotificationName"){ 
      //code to execute on notification 
} 
+0

se l'aggiornamento dell'app in background è abilitato, quindi, al ricevimento di una notifica darwin, l'app si attiva dallo sfondo per eseguire codice come con le notifiche remote? – user2363025