Processing of <null> During iOS data parsing, and null for ios data parsing
During iOS development, data is often required to communicate with the server. JSON is a common and efficient and concise data format.
Problem:
In the project, the program has encountered a pitfall problem and unexpectedly crashes after obtaining some data. The reason is: because some fields in the database of the server are empty and then returned to the client in JSON format, such data will appear:Repairs = "<null>"
This data type is neither nil nor String. After it is parsed into an object, if the message (such as: length, count, etc.) is sent directly to this object, it will crash. The error message is:
-[NSNull length]: unrecognized selector sent to instance
Solution:
A Category called NullSafe is used.
NullSafe idea: during runtime operations, this annoying null value is set to nil, while nil is secure and can send any message to the nil object without crashing. This category is very convenient to use. You only need to add it to the project, and you do not need to do anything else. It is very simple.
NullSafe source code:
#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
For details, go to Github:
Https://github.com/nicklockwood/NullSafe