iOS NSNotificationCenter (自己實現一個通知中樞XMCNotificationCenter)

來源:互聯網
上載者:User

標籤:

   系統不是已經有通知中樞NSNotificationCenter了嗎?為什麼還要自己實現一個呢?下面我們就考慮以下例子(下面大部分是我抄下我在github上寫的說明及原碼):

在iOS中模組間通知我們用得最多的就是NSNotificationCenter。舉個例子,現在我們有一個模組需要拋一個通知出來,通知其它模組使用者名稱改變了,我們來看代碼大致是怎麼寫的

發通知一方NSString *const kUserNameChangedNotification = @"UserNameChangedNotification";NSString *const kUserOldNameKey = @"UserOldNameKey";NSString *const kUserNewNameKey = @"UserNewNameKey";NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];[notificationCenter postNotificationName:UserNameChangedNotification object:nil userInfo:@{kUserOldNameKey:@"oldName",UserNewNameKey:"newName"}];接收通知的一方可以是[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(UserNameChanged:) name:kUserNameChangedNotification object:nil];也可以是[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(UserNameChangedNotification:) name:kUserNameChangedNotification object:nil];

從例子中可以看到有的缺點:
1.對於接收同一個事件的通知,不同的人可能會用不同的方法名,無法統一。
2.對於多參數支援不方便。

出於以上兩點,寫了這個XMCNotificationCenter,對應上面情況會變成以下

發通知一方@protocol UserObserver <NSObject>- (void)userNameChangedWithOldName:(NSString *)oldName newName:(NSString *)newName;@endPostNotification(UserObserver, @selector(userNameChangedWithOldName:newName:), userNameChangedWithOldName:@"oldName", newName:@"newName");接收通知的一方是AddObserverWithProtocol(self, UserObserver);並實現UserObserver協議的userNameChangedWithOldName:newName:方法即可
釋構時移除通知RemoveObserver(self);

XMCNotificationCenter裡面方法不多,使用簡單,先定義協議如UserObserver,並添加裡面需要實現的方法,方法為required或optional都可以
接下來就是通知者,只要使用PostNotification宏,參數分別是協議、方法的SEL、方法調用(這裡還會有XCode的提示輸入)。
最後就是觀察者,使用AddObserverWithProtocol添加自己需要觀察的協議,並實現協議相關方法,如果是optional的方法,不實現也就不會接收到通知。釋構時使用RemoveObserver移除通知。

XMCNotificationCenter不能完全替代NSNotificationCenter。因為系統很多行為是靠NSNotificationCenter通知出來的。但如果通知是由我們自己發出,都可以使用XMCNotificationCenter。實現原理也很簡單,利用了宏展開的特性,用宏使得發送通知像調用函數一樣方便。具體代碼如下,代碼量不多:(也可以到我的github上的XMCNotificationCenter看)

 

////  XMCNotificationCenter.h//  XMCNotificationCenter////  Created by xianmingchen on 16/7/5.//  Copyright © 2016年 xianmingchen. All rights reserved.//#import <Foundation/Foundation.h>//添加或刪除監聽#define AddObserverWithProtocol(observer, observerProtocol) [[XMCNotificationCenter defaultCenter] addObserver:observer withProtocolKey:@protocol(observerProtocol)]#define RemoveObserverWithProtocol(observer, observerProtocol) [[XMCNotificationCenter defaultCenter] removeObserver:observer withProtocolKey:@protocol(observerProtocol)]#define RemoveObserver(observer) [[XMCNotificationCenter defaultCenter] removeObserver:observer];//拋通知#define PostNotification(observerProtocol, selector, func) \{     NSArray *__observers__ = [[XMCNotificationCenter defaultCenter] observersWithProtocolKey:@protocol(observerProtocol)];    for (id observer in __observers__)     {         if ([observer respondsToSelector:selector])         {             [observer func];         }     } }typedef Protocol *ObserverProtocolKey;@interface XMCNotificationCenter : NSObject+ (XMCNotificationCenter *)defaultCenter;- (void)addObserver:(id)observer withProtocolKey:(ObserverProtocolKey)key;- (void)removeObserver:(id)observer withProtocolKey:(ObserverProtocolKey)key;- (void)removeObserver:(id)observer;- (NSArray *)observersWithProtocolKey:(ObserverProtocolKey)key;@end
///  XMCNotificationCenter.mm//  XMCNotificationCenter////  Created by xianmingchen on 16/7/5.//  Copyright © 2016年 xianmingchen. All rights reserved.//#import "XMCNotificationCenter.h"static CFRange fullRangeWithArray(CFArrayRef array);static void ObserversCallbackFunc(const void *_key, const void *_value, void *context);struct ObserverContext {    __weak XMCNotificationCenter *center;    __unsafe_unretained id observer;};@interface XMCNotificationCenter (){    CFMutableDictionaryRef observersDictionary;    dispatch_semaphore_t semaphore;}@end@implementation XMCNotificationCenter+ (XMCNotificationCenter *)defaultCenter{    static XMCNotificationCenter *center = nil;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{       center = [[XMCNotificationCenter alloc] init];    });        return center;}- (id)init{    self = [super init];    if (self) {            CFDictionaryValueCallBacks kCallBack;        kCallBack.version = 0;        observersDictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);        semaphore = dispatch_semaphore_create(1);    }    return self;}#pragma mark - Add & Remove- (void)addObserver:(id)observer withProtocolKey:(ObserverProtocolKey)key{    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);        if (![observer conformsToProtocol:key])    {    #ifdef DEBUG        NSParameterAssert(@"observer not conformsToProtocol");    #endif        NSLog(@"client doesnot conforms to protocol: %@", NSStringFromProtocol(key));    }    CFStringRef cfStringKey =  (__bridge CFStringRef)NSStringFromProtocol(key);    CFMutableArrayRef observersArray = (CFMutableArrayRef)CFDictionaryGetValue(observersDictionary, cfStringKey);    if (observersArray == NULL)    {        observersArray = CFArrayCreateMutable(NULL, 0, NULL);        CFDictionaryAddValue(observersDictionary, cfStringKey, (const void *)observersArray);    }            CFRange range = fullRangeWithArray(observersArray);        BOOL isContains = CFArrayContainsValue(observersArray, range, (__bridge const void *)(observer));    if (!isContains)    {        CFArrayAppendValue(observersArray, (__bridge const void *)observer);    }        dispatch_semaphore_signal(semaphore);}- (void)removeObserver:(id)observer withProtocolKey:(ObserverProtocolKey)key{    CFStringRef cfStringKey =  (__bridge CFStringRef)NSStringFromProtocol(key);    [self p_removeObserver:observer withKey:cfStringKey];}- (void)p_removeObserver:(id)observer withKey:(CFStringRef)key{    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);    CFMutableArrayRef observersArray = (CFMutableArrayRef)CFDictionaryGetValue(observersDictionary, key);        CFRange range = fullRangeWithArray(observersArray);        CFIndex index = CFArrayGetFirstIndexOfValue(observersArray, range, (__bridge const void *)observer);    if (index != -1)    {        CFArrayRemoveValueAtIndex(observersArray, index);    }        dispatch_semaphore_signal(semaphore);}- (void)removeObserver:(id)observer{    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);    ObserverContext context;    context.center = self;    context.observer = observer;    CFDictionaryApplyFunction(observersDictionary, &ObserversCallbackFunc, &context);    dispatch_semaphore_signal(semaphore);}#pragma mark - get- (NSArray *)observersWithProtocolKey:(ObserverProtocolKey)key{    CFStringRef cfStringKey =  (__bridge CFStringRef)NSStringFromProtocol(key);    CFArrayRef cfArray = (CFArrayRef)CFDictionaryGetValue(observersDictionary, cfStringKey);    NSArray *array = (__bridge NSArray *)cfArray;        return array;}@end#pragma mark - otherstatic CFRange fullRangeWithArray(CFArrayRef array){    CFRange range;    if (array == NULL)    {        return range;    }        CFIndex length = CFArrayGetCount(array) - 1;    if (length < 0) {        length = 0;    }    range.location = 0;        range.length = length;    return range;}static void ObserversCallbackFunc(const void *_key, const void *_value, void *context) {    if (!context || !_value || !_key)    {        return;    }        XMCNotificationCenter *center = ((ObserverContext *)context)->center;    id observer = ((ObserverContext *)context)->observer;    [center p_removeObserver:observer withKey:(CFStringRef)_key];}

希望對大家有協助。

 

iOS NSNotificationCenter (自己實現一個通知中樞XMCNotificationCenter)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.