前言
其实才短短工作了几个月的时间,就有不少人问我关于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(测试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传送门.
网友评论