在iOS開發過程中經常需要與服務器進行數據通訊,JSON就是一種常用的高效簡潔的數據格式。
問題:
在項目中,一直遇到一個坑的問題,程序在獲取某些數據之后莫名崩潰。原因是:由於服務器的數據庫中有些字段為空,然后以JSON形式返回給客戶端時就會出現這樣的數據:repairs = "<null>"
這個數據類型不是nil 也不是 String。 解析成對象之后,如果直接向這個對象發送消息(eg:length,count 等等)就會直接崩潰。提示錯誤為:
-[NSNull length]: unrecognized selector sent to instance
解決方案:
用了一個Category,叫做NullSafe 。
NullSafe思路:在運行時操作,把這個討厭的空值置為nil,而nil是安全的,可以向nil對象發送任何message而不會奔潰。這個category使用起來非常方便,只要加入到了工程中就可以了,你其他的什么都不用做,很簡單。
NullSafe 源碼:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
#ifndef NULLSAFE_ENABLED
#define NULLSAFE_ENABLED 1
#endif
#pragma GCC diagnostic ignored "-Wgnu-conditional-omitted-operand"
@implementation NSNull (NullSafe)
#if NULLSAFE_ENABLED
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
@synchronized([self class])
{
//look up method signature
NSMethodSignature *signature = [super methodSignatureForSelector:selector];
if (!signature)
{
//not supported by NSNull, search other classes
static NSMutableSet *classList = nil;
static NSMutableDictionary *signatureCache = nil;
if (signatureCache == nil)
{
classList = [[NSMutableSet alloc] init];
signatureCache = [[NSMutableDictionary alloc] init];
//get class list
int numClasses = objc_getClassList(NULL, 0);
Class *classes = (Class *)malloc(sizeof(Class) * (unsigned long)numClasses);
numClasses = objc_getClassList(classes, numClasses);
//add to list for checking
NSMutableSet *excluded = [NSMutableSet set];
for (int i = 0; i < numClasses; i++)
{
//determine if class has a superclass
Class someClass = classes[i];
Class superclass = class_getSuperclass(someClass);
while (superclass)
{
if (superclass == [NSObject class])
{
[classList addObject:someClass];
break;
}
[excluded addObject:NSStringFromClass(superclass)];
superclass = class_getSuperclass(superclass);
}
}
//remove all classes that have subclasses
for (Class someClass in excluded)
{
[classList removeObject:someClass];
}
//free class list
free(classes);
}
//check implementation cache first
NSString *selectorString = NSStringFromSelector(selector);
signature = signatureCache[selectorString];
if (!signature)
{
//find implementation
for (Class someClass in classList)
{
if ([someClass instancesRespondToSelector:selector])
{
signature = [someClass instanceMethodSignatureForSelector:selector];
break;
}
}
//cache for next time
signatureCache[selectorString] = signature ?: [NSNull null];
}
else if ([signature isKindOfClass:[NSNull class]])
{
signature = nil;
}
}
return signature;
}
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
invocation.target = nil;
[invocation invoke];
}
#endif
@end
詳細的請去Github上查看:
https://github.com/nicklockwood/NullSafe

