手动实现NSNotificationCenter功能

这几天学习的时候看到了某位程序员自制的手动实现带有block回调函数参数的KVO模式,虽然也跟着做了出来,但是缺陷还有很明显的,无法监听非对象。这个暂且不谈,KVO的实现让我有了实现通知机制的想法,NSNotification想来也就是将接收通知的对象加入某个列表中(我用NSArray存储),然后每个通知对象对应一个回调函数列表,每一次接收新通知时遍历查找,代码放上来:

LXD_NotificationCenter.h

@interface LXD_NotificationCenter : NSObject

+ (LXD_NotificationCenter *)defaultCenter;

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;

- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSString *)aName object:(id)anObject;
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;

@end
LXD_NotificationCenter.m

#import "LXD_NotificationCenter.h"
#import "LXD_Notification.h"
#import <objc/message.h>
#import <objc/runtime.h>

static LXD_NotificationCenter * defaultCenter = nil;
static NSString * const kNotificationKey = @"LXDNotificationKey";


#pragma mark -- Store Each Observer's SEL
@interface LXD_Observer : NSObject

@property (nonatomic, assign) SEL aSelector;
@property (nonatomic, weak) NSObject * observer;
@property (nonatomic, strong) LXD_Notification * notification;

@end


@implementation LXD_Observer

- (instancetype)initWithObserver: (NSObject *)anObserver selector: (SEL)aSelector name: (NSString *)aName object: (NSObject *)anObject userInfo: (NSDictionary *)userInfo
{
    if (self = [super init]) {
        
        self.notification = [[LXD_Notification alloc] initWithName: aName object: anObject userInfo: userInfo];
        _aSelector = aSelector;
        _observer = anObserver;
    }
    return self;
}

@end



#pragma mark -- NotificationCenterMethods
@implementation LXD_NotificationCenter

- (instancetype)init
{
    if (defaultCenter == nil) {
        
        defaultCenter = [super init];
    }
    return defaultCenter;
}


- (instancetype)copy
{
    return defaultCenter;
}


+ (instancetype)new
{
    return [self defaultCenter];
}


- (void)dealloc
{
    
}


+ (LXD_NotificationCenter *)defaultCenter
{
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        
        defaultCenter = [[LXD_NotificationCenter alloc] init];
    });
    return defaultCenter;
}


- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject
{
    LXD_Observer * newObserver = [[LXD_Observer alloc] initWithObserver: observer selector: aSelector name: aName object: anObject userInfo: nil];
    NSMutableArray * observers = objc_getAssociatedObject(self, (__bridge void *)kNotificationKey);
    if (observers == nil) {
        
        observers = [NSMutableArray array];
        objc_setAssociatedObject(self, (__bridge void *)kNotificationKey, observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    [observers addObject: newObserver];
}


- (void)postNotification:(LXD_Notification *)notification
{
    NSMutableArray * observers = objc_getAssociatedObject(self, (__bridge void *)kNotificationKey);
    for (int i = 0; i < observers.count; i++) {
        
        LXD_Observer * observer = observers[i];
        if ([observer.notification.name isEqualToString: notification.name]) {
            
            observer.notification = nil;
            observer.notification = notification;
            [self sendMsgWithObserver: observer];
            break;
        }
    }
}


- (BOOL)hasParam: (SEL)aSelector
{
    NSString * selectorStr = @(sel_getName(aSelector));
    return [selectorStr hasSuffix: @":"];
}


- (void)postNotificationName:(NSString *)aName object:(id)anObject
{
    NSMutableArray * observers = objc_getAssociatedObject(self, (__bridge void *)kNotificationKey);
    for (int i = 0; i < observers.count; i++) {
        
        LXD_Observer * observer = observers[i];
        if ([observer.notification.name isEqualToString: aName]) {
            
            observer.notification.object = anObject;
            [self sendMsgWithObserver: observer];
            break;
        }
    }
}


- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo
{
    NSMutableArray * observers = objc_getAssociatedObject(self, (__bridge void *)kNotificationKey);
    for (int i = 0; i < observers.count; i++) {
        
        LXD_Observer * observer = observers[i];
        if ([observer.notification.name isEqualToString: aName]) {
            
            observer.notification.object = anObject;
            observer.notification.userInfo = aUserInfo;
            [self sendMsgWithObserver: observer];
            break;
        }
    }
}


- (void)removeObserver:(id)observer
{
    
}


- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject
{
    
}


- (void)sendMsgWithObserver: (LXD_Observer *)observer{
    NSLog(@"%s", sel_getName(observer.aSelector));
    if ([self hasParam: observer.aSelector]) {
        
        void (*objcMsgSend) (id, SEL, LXD_Notification *) = (void *)objc_msgSend;
        objcMsgSend(observer.observer, observer.aSelector, observer.notification);
        
    } else {
        
        void (*objcMsgSend) (id, SEL) = (void *)objc_msgSend;
        objcMsgSend(observer.observer, observer.aSelector);
        
    }
}
上面我因为实现的时候恰好有事完成到一半就没有继续了,大家可以参照一下把这代码加上。

LXD_Notification.h

#import <Foundation/Foundation.h>

@interface LXD_Notification : NSObject

@property (nonatomic, copy, readonly) NSString * name;
@property (nonatomic, weak) NSObject * object;
@property (nonatomic, copy) NSDictionary * userInfo;

- (instancetype)init;
- (instancetype)initWithName: (NSString *)name object: (NSObject *)object;
- (instancetype)initWithName: (NSString *)name object: (NSObject *)object userInfo:(NSDictionary *)userInfo;
+ (instancetype)notificationWithName: (NSString *)name object:(id)anObject;
+ (instancetype)notificationWithName:(NSString *)name object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

@end
LXD_Notification.m

#import "LXD_Notification.h"

@implementation LXD_Notification

- (instancetype)init
{
    return [self initWithName: @"" object: nil userInfo: nil];
}

- (instancetype)initWithName:(NSString *)name object:(NSObject *)object
{
    return [self initWithName: name object: object userInfo: nil];
}

- (instancetype)initWithName: (NSString *)name object: (NSObject *)object userInfo:(NSDictionary *)userInfo
{
    if (self = [super init]) {
        
        _name = name;
        _object = object;
        _userInfo = userInfo;
    }
    return self;
}

+ (instancetype)notificationWithName: (NSString *)name object:(id)anObject
{
    return [[self alloc] initWithName: name object: anObject userInfo: nil];
}

+ (instancetype)notificationWithName:(NSString *)name object:(id)anObject userInfo:(NSDictionary *)aUserInfo
{
    return [[self alloc] initWithName: name object: anObject userInfo: aUserInfo];
}

@end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值