众所周知,服务器返回的数据时不时的就不靠谱一下,返回NSNull类型引起客户端crash,这种定时炸弹我们如果通过:
[des isKindOfClass:[NSNull class]]
这样判断只能解决某个问题,然而对于不确定的返回null无法下手,另外到处写这种代码看起来也是很不爽。
解决:利用消息转发
消息转发不了解的可以自行百度
在写的时候,我们要考虑@"",@0,@{},@[]这几种常用的类型空值, NSNull实例在调用到一些不属于它的方法的时候, 如果@"",@0,@{},@[]可以响应的时候就丢给他们去处理去。
比如 调用 intvalue,可以丢给@0去处理。
详细代码说明
#import "NSNull+safe.h"
#define NullObjects @[@"",@0,@{},@[]]
@implementation NSNull (safe)
//必须返回一个方法签名不能为空
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
NSMethodSignature *signature = [super methodSignatureForSelector:selector];
if (signature != nil) return signature;
for (NSObject *object in NullObjects) {
signature = [object methodSignatureForSelector:selector];
if (signature) {
//strcmp比较两个字符串,相同返回0
//这里 @ 是指返回值为对象 id
if (strcmp(signature.methodReturnType, "@") == 0) {
signature = [[NSNull null] methodSignatureForSelector:@selector(__returnNil)];
}
break;
}
}
return signature;
}
//消息转发的最后一步
- (void)forwardInvocation:(NSInvocation *)anInvocation {
//如果返回值是对象 设置方法为__returnNil
if (strcmp(anInvocation.methodSignature.methodReturnType, "@") == 0) {
anInvocation.selector = @selector(__returnNil);
[anInvocation invokeWithTarget:self];
return;
}
//遍历 查看 @"",@0,@{},@[] 那个响应了selector,然后丢给它去执行
for (NSObject *object in NullObjects) {
if ([object respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:object];
return;
}
}
//抛出异常
[self doesNotRecognizeSelector:anInvocation.selector];
}
- (id)__returnNil {
return nil;
}
@end
[demo 地址] (https://github.com/CorkiiOS/NSNullSafeDemo.git)
欢迎star