
前言
其實(shí)才短短工作了幾個(gè)月的時(shí)間,就有不少人問我關(guān)于nil的處理問題,因?yàn)閱柕娜撕芏?為了方便后來之人,(PS:騷棟你不要把自己說得那么高尚,你不就是為了圖省事嗎?以后有人問你這個(gè)問題,你好直接好甩博客給人家?you see see you !)咳咳,好了下面我就要說說我對(duì)nil的處理幾種方式.
nil 出現(xiàn)原因
其實(shí) nil大部分是出現(xiàn)在網(wǎng)絡(luò)請(qǐng)求這一部分,出現(xiàn)nil的情況主要是有兩種,一種是沒有網(wǎng)絡(luò)的情況下,仍然向服務(wù)器請(qǐng)求數(shù)據(jù),這樣請(qǐng)求下來的整體數(shù)據(jù)就為nil,另外一種就是由于后臺(tái)人員的不小心或者一些意外因素,導(dǎo)致請(qǐng)求下來的數(shù)據(jù)有一個(gè)nil的存在(不是全部數(shù)據(jù)昂),這時(shí)候如果使用你來nil賦值,程序雖然不會(huì)崩潰,但是一個(gè)空白值,不管如何都是我們不想要的結(jié)果.
下面我就對(duì)這兩種出現(xiàn)情況的處理逐一說明.
無網(wǎng)絡(luò),數(shù)據(jù)為nil的解決方案
這里我要說明一下,是無網(wǎng)絡(luò),而不是服務(wù)器未響應(yīng),如果是服務(wù)器無響應(yīng),那么給對(duì)應(yīng)的NSError對(duì)象賦值,這里無網(wǎng)絡(luò)的情況可不會(huì)給NSError對(duì)象賦值.
解決方案其實(shí)很簡(jiǎn)單,只要我們把加上一個(gè)if語(yǔ)句即可.這里我用AFNetworking做一下范例,(請(qǐng)求地址無效,純粹是為講解)
在加代碼保護(hù)之前,如下圖所示.其中responseObject為請(qǐng)求的網(wǎng)絡(luò)數(shù)據(jù),可能為空,如果是nil的話,直接進(jìn)行解析程序會(huì)直接崩潰的.

接下來,我們只需要做簡(jiǎn)單的一步就可以解決這個(gè)問題,一個(gè)判斷分支.如下所示.(是不是很簡(jiǎn)單呢?)

服務(wù)器數(shù)據(jù)問題,數(shù)據(jù)為nil的解決方案
有時(shí)候呢,在服務(wù)器端 數(shù)據(jù)可能本身就是為nil,但是服務(wù)器人員跟你說,沒有空值,大膽的用吧,然后哐當(dāng)?shù)囊宦?翻車了.
對(duì)于這種我們?cè)撊绾谓鉀Q呢?
這里我提供幾個(gè)方案.大家參考使用即可.(以NSString類型為例)
1.對(duì)NSString寫個(gè)延展(Category).
延展的.h和.m代碼如下所示.我們主要是在這個(gè)延展方法中判斷當(dāng)前的NSString對(duì)象是否nil,如果是那么對(duì)對(duì)象進(jìn)行相應(yīng)的空值操作,如果不是,直接返回.
#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
使用的時(shí)候,我們首先導(dǎo)入延展的頭文件#import "NSString+NilSafe.h",然后我們?nèi)缦率褂?
NSString *testString = nil;
self.label.text = [NSString NilSafeWithString:testString];
但是如果數(shù)據(jù)一多這種解決方案就不太方便了,我們不能每一個(gè)控制器都導(dǎo)入頭文件吧,還沒每一個(gè)地方都寫這么一堆代碼是吧,所以這種解決方案只是適合范圍較小的情況.
2.使用NullSafe.m
NullSafe這是一個(gè)歪果仁寫的一個(gè)Category,我們只要把NullSafe.m拖進(jìn)我們的工程即可.點(diǎn)擊下載NullSafe.然后我們就不需要做任何操作了,只要有空值nil,他就會(huì)自動(dòng)轉(zhuǎn)換.
但是NullSafe真的是我們想要的結(jié)果嗎?不不不,NullSafe雖然把空值轉(zhuǎn)換成不崩潰的數(shù)據(jù),但是你們看看轉(zhuǎn)換成了什么了."<null>"是不可以直接編輯的,也就說它并不能直接轉(zhuǎn)換成其他類型,然后你的頁(yè)面就是各種"<null>".

NullSafe綜合來說還是很方便的,但是卻不能解決一些小問題.
3.重寫數(shù)據(jù)模型model中的-(void)setValue:(id)value forKey:(NSString *)key方法
iOS中,我們都知道我們?cè)谧鼍W(wǎng)絡(luò)請(qǐng)求的時(shí)候呢,喜歡使用model來存儲(chǔ)數(shù)據(jù).那么我們經(jīng)常創(chuàng)建的model中寫容錯(cuò)處理方法-(void)setValue:(id)value forUndefinedKey:(NSString *)key,但是-(void)setValue:(id)value forKey:(NSString *)key方法,卻是不經(jīng)常寫的.但是我們今天要用到的是賦值方法.
通常呢,我們把網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求解析完,我們會(huì)把對(duì)應(yīng)的字典使用- (void)setValuesForKeysWithDictionary:這個(gè)方法直接賦值給我們的model如下圖所示.(因?yàn)檎?qǐng)求地址為無效值,所以不可能成功,只做參考)

我們都知道- (void)setValuesForKeysWithDictionary:這個(gè)使用字典賦值的方法其實(shí)是封裝的-(void)setValue:(id)value forKey:(NSString *)key這個(gè)方法的,所以我們需要在model中的重寫賦值方法

現(xiàn)在的需求是 如果數(shù)據(jù)為空,那么我們就會(huì)讓用戶看到"無"這個(gè)字.,假設(shè)現(xiàn)在TestModel(測(cè)試model)的name屬性可能為nil.這樣我們就需要在.m文件中的賦值方法做以下操作.直接判斷key是否為name并且value是否為nil,滿足條件那么就做出對(duì)應(yīng)的修改.
-(void)setValue:(id)value forKey:(NSString *)key{
[super setValue:value forKey:key];
if ([key isEqualToString:@"name"] &&value ==nil) {
self.name = @"無";
}
}
但是,使用上面的解決方法如果說屬性少還好說一點(diǎn),寫幾個(gè)if就是了,實(shí)際情況中一個(gè)model有可能含有十個(gè)或者十個(gè)以上的屬性,這時(shí)候難道我們要寫十個(gè)if嗎?為此,我想了個(gè)解決方案,那就是先對(duì)value進(jìn)行判斷,然后再調(diào)用父類方法,這樣,一個(gè)if就可以把含有空值的所有的屬性都做了判斷.具體實(shí)現(xiàn)如下.
-(void)setValue:(id)value forKey:(NSString *)key{
if (value == nil) {
value = @"無";
}
[super setValue:value forKey:key];
}
但是,這樣的解決方案也是有問題的,比如說我想name屬性為nil的時(shí)候,轉(zhuǎn)化為字符串"姓名無",address為nil的時(shí)候,轉(zhuǎn)化為"地址未填寫".這種情況就是解決不了的,如果解決,又會(huì)回到第一個(gè)方式了.
總結(jié):總體上來說,四種解決方法各有利弊,只要根據(jù)實(shí)際情況不同的選擇即可.
結(jié)束語(yǔ)
好了,大家終于知道在iOS中空值nil到底有讓人多么藍(lán)瘦香菇了吧,最后附上Demo傳送門.