Object-C中nil, NULL跟NSNull

相信不少開發者,都被NSNull坑過,最常見的是服務器返回的json裏面,說好的字典、數組、數字,結果返回的是空值。
 
這個時候,NSJSONSerialization 會自動把他們換成 NSNull。當我們再去用dict[@“hello”]的時候,就會出觸發exception,導致程序崩潰。
 
那麼如何處理它呢?
我曾經的做法
寫了個宏,判斷返回的這個類是不是NSNull類,即 isKindOfClass
 
最簡單的做法
相信大家都知道,[NSNull null] 並不是一個工廠方法,而是一個單例模式,那麼我們直接去判斷賦值的這個指針是不是[NSNull null] 就好了。
 
那麼問題來了,編譯器會多了一個warning,很煩人。
 
這篇文章裏面介紹了各種做法:
  1. - (void)someMethod 
  2.     NSString *aString = @"loremipsum"
  3.  
  4.     // This will complain: "Comparison of distinct pointer types ('NSString *' and 'NSNull *')" 
  5.     if (aString != [NSNull null]) 
  6.     { 
  7.  
  8.     } 
  9.  
  10.     // This works (at least for strings), but isEqual: does different things  
  11.     // for different classes, so it's not ideal 
  12.     if ([aString isEqual:[NSNull null]]) 
  13.     { 
  14.  
  15.     } 
  16.  
  17.     // If you cast it to the class you're comparing against 
  18.     // then you're good to go 
  19.     if (aString != (NSString *)[NSNull null]) 
  20.     { 
  21.  
  22.     } 
  23.  
  24.     // But we can also just cast it to id and 
  25.     // that works generically 
  26.     if (aString != (id)[NSNull null]) 
  27.     { 
  28.  
  29.     } 
  30.  
  31.     // The thing that would be really cool, 
  32.     // would be [NSNull null] returning 
  33.     // id (like in the sample category below). 
  34.     // Wouldn't count on that one though. 
  35.     if (aString != [NSNull idNull]) 
  36.     { 
  37.  
  38.     } 
 
這些都不是非常漂亮的解決方案,這篇文章的作者推薦:
  1. @interface NSNull (idNull) 
  2. + (id)idNull; 
  3. @end 
  4. @implementation NSNull (idNull) 
  5. + (id)idNull { return [NSNull null]; } 
  6. @end 
 
或者呢
  1. if ([[NSNull null] isEqual:aString]) 
  2.  
 
最終解決方案
上面的做法,都需要判斷一次,還是很不優雅,爲什麼呢,我們還是不能像NULL,nil一樣,直接拿來用,還是需要判斷一下,這裏推薦一套最漂亮的作法。
 
陳航提供了一個gist
 
我發現我的octopress的gist插件掛了,直接貼出來好了。
  1. #define NSNullObjects @[@"",@0,@{},@[]] 
  2.  
  3. @interface NSNull (InternalNullExtention) 
  4. @end 
  5.  
  6. @implementation NSNull (InternalNullExtention) 
  7.  
  8. - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector 
  9.     NSMethodSignature* signature = [super methodSignatureForSelector:selector]; 
  10.     if (!signature) { 
  11.         for (NSObject *object in NSNullObjects) { 
  12.             signature = [object methodSignatureForSelector:selector]; 
  13.             if (signature) { 
  14.                 break
  15.             } 
  16.         } 
  17.  
  18.     } 
  19.     return signature; 
  20.  
  21. - (void)forwardInvocation:(NSInvocation *)anInvocation 
  22.     SEL aSelector = [anInvocation selector]; 
  23.  
  24.     for (NSObject *object in NSNullObjects) { 
  25.         if ([object respondsToSelector:aSelector]) { 
  26.             [anInvocation invokeWithTarget:object]; 
  27.             return
  28.         } 
  29.     } 
  30.  
  31.     [self doesNotRecognizeSelector:aSelector]; 
  32. @end 
 
很高端霸氣上檔次的做法,通過處理異常情況,來實現這個功能。
 
這裏還提供一個日本人的封裝方案
  1. #import "NSNull+OVNatural.h" 
  2.  
  3. @implementation NSNull (OVNatural) 
  4. - (void)forwardInvocation:(NSInvocation *)invocation 
  5.     if ([self respondsToSelector:[invocation selector]]) { 
  6.         [invocation invokeWithTarget:self]; 
  7.     } 
  8.  
  9. - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector 
  10.     NSMethodSignature *sig = [[NSNull class] instanceMethodSignatureForSelector:selector]; 
  11.     if(sig == nil) { 
  12.         sig = [NSMethodSignature signatureWithObjCTypes:"@^v^c"]; 
  13.     } 
  14.     return sig; 
  15.  
  16. @end 
 
關於[NSMethodSignature signatureWithObjCTypes:“@^vc”]的功能,可以參考以下兩篇文章:




//判斷對象不空
if(object) {}

//判斷對象爲空
if(object == nil) {}

//數組初始化,空值結束
NSArray *pageNames=[[NSArray alloc] initWithObjects:@"DocumentList",@"AdvancedSearch",@"Statistics",nil];

//判斷數組元素是否爲空
UIViewController *controller=[NSArray objectAtIndex:i];
if((NSNull *)controller == [NSNull null])
{
    //
}

//判斷字典對象的元素是否爲空
NSString *userId=[NSDictionary objectForKey:@"UserId"];
if(userId == [NSNull null])
{
    //
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章