工欲善其事,必先利其器系列之 Runtime 实现Notifi
2017-09-04 本文已影响5人
SmileFans
SmileNotification
导读:
如果不用Notification,是否能实现Notification消息的接收与发送呢? 尝试着用runtime试验了一把,答案是可以的,不用考虑烦人的销毁delloc通知,无需考虑发送通知所带的参数,可随意自定义类型,model,字符串,数组等等,只需要对应住消息的标识Key,即可实现
下面是尝试过程
在runtime 中:
void objc_setAssociatedObject(id object, const void key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void key);
这两个方法可以让一个对象和另一个对象关联,就是说一个对象可以保持对另一个对象的引用,并获取那个对象。
objc_setAssociatedObject来把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。当然,此处的关键字和关联策略是需要进一步讨论的。
■ 关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。
■ 关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。这种关联策略是通过使用预先定义好的常量来表示的。
思路来了,那么就实现以下试试,既然是关联对象,那就做一个中间代理层,负责消息交互
@protocol SmileMessageCenterDelegate <NSObject>
@optional
/**
接收到message对象
*/
- (void)Smile_ReceiveMessage:(id)message messageId:(NSString *)msgId;
@end
@interface SmileNotificationHelper : NSObject
/**
添加消息接收者
@param msgReceiver 消息接收对象
@param receiverKey 消息接收对象key
*/
+ (void)add_MessageReceiver:(id<SmileMessageCenterDelegate>)msgReceiver receiverKey:(NSString *)receiverKey;
/**
发送消息
@param msg 消息对象
@param msgId 消息id
@param receiverKey 消息接收对象key
*/
+ (void)send_Message:(id)msg messageId:(NSString *)msgId receiverKey:(NSString *)receiverKey;
/**
删除消息接收者
@param receiverKey 消息接收者名
*/
+ (void)remove_MessageReceiverWithKey:(NSString *)receiverKey;
@end
在需要用到消息的地方,注册通知,根据相应的receiverKey通过category绑定对象,并在接收地方实现代理方法即可,
通知中心有了,下面就是要写一个category了
#import "NSObject+SmileNotification.h"
#import "SmileNotificationHelper.h"
#import <objc/runtime.h>
@interface NSObject ()<SmileMessageCenterDelegate>
@property (nonatomic, weak) id<SmileMessageCenterDelegate> SmileMessageCenterDelegate;
@end
@implementation NSObject (SmileNotification)
- (void)setSmileMessageCenterDelegate:(id<SmileMessageCenterDelegate>)SmileMessageCenterDelegate{
objc_setAssociatedObject(self, @selector(SmileMessageCenterDelegate), SmileMessageCenterDelegate, OBJC_ASSOCIATION_ASSIGN);
}
- (id<SmileMessageCenterDelegate>)SmileMessageCenterDelegate{
return objc_getAssociatedObject(self, @selector(SmileMessageCenterDelegate));
}
#pragma mark - 注册消息中心
- (void)register_MessageReceiverWithKey:(NSString *)receiverKey{
//将自己设置成为代理
self.SmileMessageCenterDelegate = self;
if (!CHECK_VALID_STRING(receiverKey)) {
receiverKey = [self getClassName];
}
[SmileNotificationHelper add_MessageReceiver:self.SmileMessageCenterDelegate
receiverKey:receiverKey];
}
#pragma mark - 发送消息
- (void)send_Message:(id)msg messageId:(NSString *)msgId receiverKey:(NSString *)receiverKey{
if (!CHECK_VALID_STRING(receiverKey)) {
receiverKey = [self getClassName];
}
[SmileNotificationHelper send_Message:msg messageId:msgId receiverKey:receiverKey];
}
#pragma mark - 移除消息
- (void)remove_MessageReceiverWithKey:(NSString *)receiverKey{
if (!CHECK_VALID_STRING(receiverKey)) {
receiverKey = NSStringFromClass([self class]);
}
[SmileNotificationHelper remove_MessageReceiverWithKey:receiverKey];
}
#pragma mark - private methods
- (NSString *)getClassName{
return NSStringFromClass([self class]);
}
发送者:
[self send_Message:@"💗--晨阳是个Gay~" messageId:SmileMessageTestView_Other receiverKey:@"MessageTestView"];
接受者:
//注册
[self register_MessageReceiverWithKey:@"MessageTestView"];
//实现代理方法:
//
根据不同的标识实现不同的方法
- (void)Smile_ReceiveMessage:(id)message messageId:(NSString *)msgId{
if ([msgId isEqualToString:SmileMessageTestView_Update]) {
_textField1.text = @"🐘这是一个刷新的值的通知";
}else if ([msgId isEqualToString:SmileMessageTestView_Reset]){
_textField1.text = @"✈️这是一个重置的通知";
}
else if ([msgId isEqualToString:SmileMessageTestView_Other]){
//message 可带任何类型
NSString *messageModel = (NSString *)message;
_textField1.text = messageModel;
}
}
demo传送门: