2014-10-29 26 views
10

Wyciągając moje włosy, uzyskując CFNotificationCenterAddObserver do pracy w Swift.Jak prawidłowo korzystać z narzędzia CFNotificationCenterAddObserver w Swift na iOS

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

iOS docs ma go na liście i próbowałem niezliczone iteracji na zwrotnego i niebezpiecznego wskaźnik bez powodzenia.

Powyższe wyniki wywołania funkcji w tym komunikatem o błędzie, który wydaje się być prawidłowa startowych:

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

Próbowałem też pomostowego do objc jak this post here sugeruje, ale bez powodzenia.

Oto mój most:

LockNotifierCallback.h:

#import <Foundation/Foundation.h> 

@interface LockNotifierCallback : NSObject 

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

@end 

i 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 

aktualne wezwanie CFNotificationCenterAddObserver następująco:

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

i oczywiście LockNotifierCallback.h jest w moim nagłówku Bridging. Błąd kontynuuje:

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

'CFNotificationCenterAddObserver' zajmuje' CFunctionPointer' który tak naprawdę nie możesz stworzyć z Swift (zobacz http://stackoverflow.com/a/25514748/3300036). Możesz obejść to, wykonując jakiś Objective-C, który jest podobny do tego: http://stackoverflow.com/a/26139259/3300036 –

+1

Dzięki Mark, ale dlaczego miałby być pod szybką deklaracją w dokumentach ios? https://developer.apple.com/Library/ios/documentation/CoreFoundation/Reference/CFNotificationCenterRef/index.html#//apple_ref/c/func/CFNotificationCenterAddObserver – zooster

+1

Nadal można go używać od Swift, wystarczy go przekazać funkcja zdefiniowana w C lub Objective-C, a nie funkcja Swift zamknięcia. –

Odpowiedz

9

miałem pewne problemy z DarwinNotifications, można spróbować użyć tej klasy otoki właśnie to plik nagłówka w pliku pomostowego. I możesz go użyć w szybkim tempie.

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 

w Swift można go używać tak:

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

jeśli odświeżanie aplikacji w tle jest włączone, to po otrzymaniu powiadomienia darwin aplikacja się obudzi z tła, aby wykonać kod podobny do tego w przypadku zdalnego powiadomienia? – user2363025