动机
无论出于容错的目的,还是偷懒的目的,你都想你的NSNull
的对象接受一切消息而不Crash了,就如你发消息给nil
一样。那么,就写个NSNull (FilterMessages)
的Category,简单又直接,引入项目里头就好了。
源码
#import <Foundation/Foundation.h>
@interface NSNull (FilterMessages)
@end
#import "NSNull+FilterMessages.h"
@implementation NSNull (FilterMessages)
- (id)forwardingTargetForSelector:(SEL)aSelector {
return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [NSNull instanceMethodSignatureForSelector:@selector(description)];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
id temp = nil;
[anInvocation invokeWithTarget:temp];
}
@end
测试
在main.m
的main
函数里加入代码,运行一下看看:
NSDictionary *obj = (NSDictionary *)[NSNull null]; // 欺骗一下编译器
id value = [obj objectForKey:@"anything"]; // 发消息给NSNull单例对象
好的,没Crash。
原理
先贴两个Reference,你们仔细看看,然后我再罗嗦一句:
Objective-C 消息发送与转发机制原理 (这位博主看来是个逆向高手啊:P)
StackOverflow: Objective-C respondsToSelector(时间紧的同学就看这个参考吧)
罗嗦一句:利用Objective-C的消息转发机制,把所有NSNull
对象所有不处理的消息全部转发给了nil
。