iOS 开发 @IT·互联网程序员

nil:你到底是让我有多么蓝瘦香菇?

2016-10-13  本文已影响1102人  神经骚栋
注明:图中的两个全为nil

前言


其实才短短工作了几个月的时间,就有不少人问我关于nil的处理问题,因为问的人很多,为了方便后来之人,(PS:骚栋你不要把自己说得那么高尚,你不就是为了图省事吗?以后有人问你这个问题,你好直接好甩博客给人家?you see see you !)咳咳,好了下面我就要说说我对nil的处理几种方式.

nil 出现原因


其实 nil大部分是出现在网络请求这一部分,出现nil的情况主要是有两种,一种是没有网络的情况下,仍然向服务器请求数据,这样请求下来的整体数据就为nil,另外一种就是由于后台人员的不小心或者一些意外因素,导致请求下来的数据有一个nil的存在(不是全部数据昂),这时候如果使用你来nil赋值,程序虽然不会崩溃,但是一个空白值,不管如何都是我们不想要的结果.

下面我就对这两种出现情况的处理逐一说明.

无网络,数据为nil的解决方案


这里我要说明一下,是无网络,而不是服务器未响应,如果是服务器无响应,那么给对应的NSError对象赋值,这里无网络的情况可不会给NSError对象赋值.
解决方案其实很简单,只要我们把加上一个if语句即可.这里我用AFNetworking做一下范例,(请求地址无效,纯粹是为讲解)

在加代码保护之前,如下图所示.其中responseObject为请求的网络数据,可能为空,如果是nil的话,直接进行解析程序会直接崩溃的.

接下来,我们只需要做简单的一步就可以解决这个问题,一个判断分支.如下所示.(是不是很简单呢?)

服务器数据问题,数据为nil的解决方案


有时候呢,在服务器端 数据可能本身就是为nil,但是服务器人员跟你说,没有空值,大胆的用吧,然后哐当的一声,翻车了.

对于这种我们该如何解决呢?
这里我提供几个方案.大家参考使用即可.(以NSString类型为例)

1.对NSString写个延展(Category).

延展的.h和.m代码如下所示.我们主要是在这个延展方法中判断当前的NSString对象是否nil,如果是那么对对象进行相应的空值操作,如果不是,直接返回.

#import <Foundation/Foundation.h>

@interface NSString (NilSafe)

+(NSString *)NilSafeWithString:(NSString *)string;

@end

#import "NSString+NilSafe.h"

@implementation NSString (NilSafe)

+(NSString* )NilSafeWithString:(NSString *)string{

    if (string == nil) {
        return [NSString stringWithFormat:@"无"];
    }else{

        return string;
    }

}

@end

使用的时候,我们首先导入延展的头文件#import "NSString+NilSafe.h",然后我们如下使用.

    NSString *testString = nil;
    self.label.text = [NSString NilSafeWithString:testString];

但是如果数据一多这种解决方案就不太方便了,我们不能每一个控制器都导入头文件吧,还没每一个地方都写这么一堆代码是吧,所以这种解决方案只是适合范围较小的情况.

2.使用NullSafe.m

NullSafe这是一个歪果仁写的一个Category,我们只要把NullSafe.m拖进我们的工程即可.点击下载NullSafe.然后我们就不需要做任何操作了,只要有空值nil,他就会自动转换.

但是NullSafe真的是我们想要的结果吗?不不不,NullSafe虽然把空值转换成不崩溃的数据,但是你们看看转换成了什么了."<null>"是不可以直接编辑的,也就说它并不能直接转换成其他类型,然后你的页面就是各种"<null>".

NullSafe综合来说还是很方便的,但是却不能解决一些小问题.

3.重写数据模型model中的-(void)setValue:(id)value forKey:(NSString *)key方法

iOS中,我们都知道我们在做网络请求的时候呢,喜欢使用model来存储数据.那么我们经常创建的model中写容错处理方法-(void)setValue:(id)value forUndefinedKey:(NSString *)key,但是-(void)setValue:(id)value forKey:(NSString *)key方法,却是不经常写的.但是我们今天要用到的是赋值方法.

通常呢,我们把网络数据请求解析完,我们会把对应的字典使用- (void)setValuesForKeysWithDictionary:这个方法直接赋值给我们的model如下图所示.(因为请求地址为无效值,所以不可能成功,只做参考)

我们都知道- (void)setValuesForKeysWithDictionary:这个使用字典赋值的方法其实是封装的-(void)setValue:(id)value forKey:(NSString *)key这个方法的,所以我们需要在model中的重写赋值方法

TestModel.h文件中的所有属性

现在的需求是 如果数据为空,那么我们就会让用户看到"无"这个字.,假设现在TestModel(测试model)的name属性可能为nil.这样我们就需要在.m文件中的赋值方法做以下操作.直接判断key是否为name并且value是否为nil,满足条件那么就做出对应的修改.

-(void)setValue:(id)value forKey:(NSString *)key{

    [super setValue:value forKey:key];
    
    if ([key isEqualToString:@"name"] &&value ==nil) {
        
        self.name = @"无";
        
    }
}

但是,使用上面的解决方法如果说属性少还好说一点,写几个if就是了,实际情况中一个model有可能含有十个或者十个以上的属性,这时候难道我们要写十个if吗?为此,我想了个解决方案,那就是先对value进行判断,然后再调用父类方法,这样,一个if就可以把含有空值的所有的属性都做了判断.具体实现如下.

-(void)setValue:(id)value forKey:(NSString *)key{

    if (value == nil) {
        value = @"无";
    }

    [super setValue:value forKey:key];
   
}

但是,这样的解决方案也是有问题的,比如说我想name属性为nil的时候,转化为字符串"姓名无",address为nil的时候,转化为"地址未填写".这种情况就是解决不了的,如果解决,又会回到第一个方式了.

总结:总体上来说,四种解决方法各有利弊,只要根据实际情况不同的选择即可.

结束语


好了,大家终于知道在iOS中空值nil到底有让人多么蓝瘦香菇了吧,最后附上Demo传送门.

--->NilSafeDemo传送门🚪

上一篇 下一篇

猜你喜欢

热点阅读