Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Appletone/2371f2ab1ba7c9a62091 to your computer and use it in GitHub Desktop.
Save Appletone/2371f2ab1ba7c9a62091 to your computer and use it in GitHub Desktop.
@import Foundation;
@interface KKWatchAppNotificationCenter : NSObject
+ (instancetype)sharedCenter;
- (void)postNotification:(NSString *)key;
- (void)addTarget:(id)target selector:(SEL)selector name:(NSString *)notification;
- (void)removeObserver:(NSObject *)observer;
@end
#import "KKWatchAppNotificationCenter.h"
#define LFSuppressPerformSelectorLeakWarning(doPerformSelector) \
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
doPerformSelector; \
_Pragma("clang diagnostic pop") \
} while (0)
@interface KKWatchAppNotificationCenter ()
{
NSMutableDictionary *notificationKeys;
}
@end
@implementation KKWatchAppNotificationCenter
+ (instancetype)sharedCenter
{
static KKWatchAppNotificationCenter *sharedRegister = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedRegister = [[KKWatchAppNotificationCenter alloc] init];
});
return sharedRegister;
}
- (instancetype)init
{
self = [super init];
if (self) {
notificationKeys = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)postNotificationWithKey:(NSString *)key
{
CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
CFDictionaryRef const userInfo = NULL;
BOOL const deliverImmediately = YES;
CFNotificationCenterPostNotification(center, (CFStringRef)key, NULL, userInfo, deliverImmediately);
}
- (void)addTarget:(id)target selector:(SEL)selector name:(NSString *)notification
{
if (!target) {
return;
}
if (!selector) {
return;
}
if (!notification || ![notification length]) {
return;
}
NSMutableArray *a = [notificationKeys objectForKey:notification];
BOOL needRegisterNotification = NO;
if (!a) {
a = [NSMutableArray array];
needRegisterNotification = YES;
}
for (NSDictionary *d in a) {
if (d[@"target"] == target && NSSelectorFromString(d[@"selector"]) == selector) {
return;
}
}
NSDictionary *d = @{@"target": target, @"selector": NSStringFromSelector(selector)};
[a addObject:d];
if (needRegisterNotification) {
[self registerNotification:notification];
[notificationKeys setObject:a forKey:notification];
}
}
- (void)removeObserver:(NSObject *)observer
{
NSMutableArray *notificationsToDelete = [[NSMutableArray alloc] init];
for (NSString *notification in notificationKeys) {
NSMutableArray *a = notificationKeys[notification];
NSMutableArray *objectsToDelete = [NSMutableArray array];
for (NSDictionary *d in a) {
id target = d[@"target"];
if (target == observer) {
[objectsToDelete addObject:d];
}
}
[a removeObjectsInArray:objectsToDelete];
if (![a count]) {
[notificationsToDelete addObject:notification];
}
}
for (NSString *notification in notificationsToDelete) {
[self unregisterNotification:notification];
[notificationKeys removeObjectForKey:notificationKeys];
}
}
- (void)registerNotification:(NSString *)key
{
CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationSuspensionBehavior const suspensionBehavior = CFNotificationSuspensionBehaviorDeliverImmediately;
CFNotificationCenterAddObserver(center, (__bridge const void *)(self), KKWatchAppNotificationRegisterCallback, (CFStringRef)key, NULL, suspensionBehavior);
}
- (void)unregisterNotification:(NSString *)key
{
CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
CFNotificationCenterRemoveObserver(center, (__bridge const void *)(self), (CFStringRef)key, NULL);
}
void KKWatchAppNotificationRegisterCallback(CFNotificationCenterRef center, void * observer, CFStringRef name, void const * object, CFDictionaryRef userInfo)
{
KKWatchAppNotificationCenter *self = (__bridge KKWatchAppNotificationCenter *)observer;
NSString *notification = (__bridge NSString *)name;
NSArray *a = [self->notificationKeys objectForKey:notification];
for (NSDictionary *d in a) {
id target = d[@"target"];
SEL action = NSSelectorFromString(d[@"selector"]);
LFSuppressPerformSelectorLeakWarning([target performSelector:action withObject:nil]);
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment