在iOS開發過程中經常需要與伺服器進行數據通訊,JSON就是一種常用的高效簡潔的數據格式。 問題: 在項目中,一直遇到一個坑的問題,程式在獲取某些數據之後莫名崩潰。原因是:由於伺服器的資料庫中有些欄位為空,然後以JSON形式返回給客戶端時就會出現這樣的數據:repairs = "<null>" 這個 ...
在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