iOS 用Runtime解决服务器返回NSNull问题

iOS 用Runtime解决服务器返回NSNull问题

奇技yin巧 指过于奇巧而无益的技艺与制品.

转载请注明出处 http://blog.csdn.net/uxyheaven/article/details/48299599

系列文章请看http://blog.csdn.net/uxyheaven/article/category/5800569

问题描述

众所周知,服务器返回的数据时不时的就不靠谱一下

{
    "名字":"漂亮妹子",
    "备胎们":,
    "年纪":18 }

明明木有备胎, 结果返回@[]也好啊, 偏偏返回一个null.
这个时候呢, 我们native端就得在取倒数据的时候, 先判断类型是不是NSArray 还得判断非空

    NSArray *boys = data[@"备胎们"];
    if ([boys isKindOfClass:[NSArray class]] && boys.count > 0)
    {
        doSomething
    }

校验的代码写多了总是很影响心情, 服务器就不能加个空的就不返回或者返回@[]么, 就不能让我们安心的写个备胎1号 = boys[0]么?

让我们来看看奇技的解决办法吧.

思路:重写NSNull的消息转发方法, 让他能处理这些异常的方法.

消息转发的相关知识不了解的同学需要自行搜索下. 在写的时候,我们要考虑 @"",@0,@{},@[]这几种常用的类型空值, 再问到NSNull的一些不属于它的方法的时候, 如果那些空值可以响应的时候就丢给他们去处理去.

// count理所当然的就等于0了
int count = boys.count;

奇技有了, 接着是yin巧.

如果我们要二号备胎囧么办?

id boy = boys[1];

这可就直接越界了啊. 我们仔细的看下NSArray里的方法, 是不是发现一个规律, 基本上返回的是id类型的是取里面的元素的. 既然这样, 那么我们就干脆只要你问NSArray里要一个元素, 我就都返回’nil’给你.

if (strcmp(anInvocation.methodSignature.methodReturnType, "@") == 0)
{
    anInvocation.selector = @selector(__uxy_nil);
    [anInvocation invokeWithTarget:self];
    return;
}

- (id)__uxy_nil
{
    return nil;
}

完整的代码如下

// .h文件
@interface NSNull (XY_InternalNullExtention)
@end

// .m文件
#define UXY_NullObjects @[@"",@0,@{},@[]]

@implementation NSNull (XY_InternalNullExtention)

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:selector];

    if (signature != nil) return signature;

    for (NSObject *object in UXY_NullObjects)
    {
        signature = [object methodSignatureForSelector:selector];

        if (signature)
        {
            if (strcmp(signature.methodReturnType, "@") == 0)
            {
                signature = [[NSNull null] methodSignatureForSelector:@selector(__returnNil)];
            }
            break;
        }
    }

    return signature;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if (strcmp(anInvocation.methodSignature.methodReturnType, "@") == 0)
    {
        anInvocation.selector = @selector(__uxy_nil);
        [anInvocation invokeWithTarget:self];
        return;
    }

    for (NSObject *object in UXY_NullObjects)
    {
        if ([object respondsToSelector:anInvocation.selector])
        {
            [anInvocation invokeWithTarget:object];
            return;
        }
    }

    [self doesNotRecognizeSelector:anInvocation.selector];
}

- (id)__uxy_nil
{
    return nil;
}

@end

测试的代码

    UXY_EXPECTED( ((NSArray *)[NSNull null])[1] == nil );
    UXY_EXPECTED( ((NSDictionary *)[NSNull null])[nil] == nil );
    UXY_EXPECTED( [((NSString *)[NSNull null]) substringToIndex:2] == nil );

这个文件在我的开源库的NSNull+XY文件里, 若果本文对你有所启发, 欢迎给个star.
https://github.com/uxyheaven/XYQuick

你可能感兴趣的:(ios,NSNull)