– :无法识别的select器发送到JSON对象
我正在开发一个iOS 5.0+应用程序与最新的SDK。
我得到这个代码一个非常奇怪的错误:
- (NSMutableURLRequest*)setupRequestWithService:(NSString*)service andMethod:(NSString*)method { NSString* url = [NSString stringWithFormat:@"%@%@.svc/%@", serverUrl, service, method]; NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; // Set authentication token. NSLog(@"???????????? %@", authenticationToken); if (authenticationToken == nil) NSLog(@"NULL AUTHTOKEN"); if ([authenticationToken isEqual:[NSNull null]]) NSLog(@"NSNULL AUTHTOKEN"); if (request == nil) NSLog(@"NULL REQUEST"); [request addValue:authenticationToken forHTTPHeaderField:REQUEST_HEADER_AUTH_TOKEN]; return request; }
这是我的日志:
???????????? <null> NSNULL AUTHTOKEN -[NSNull length]: unrecognized selector sent to instance 0x3b5a5090 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x3b5a5090'
看来authenticationToken
是NULL
。 但我不明白,如果authenticationToken
为NULL
为什么我没有看到日志上的NULL AUTHTOKEN
。
我第二次运行该方法时出现此错误,第一次,我没有得到任何错误。 这是我的日志:
???????????? (null) NULL AUTHTOKEN
顺便一提:
NSString* authenticationToken;
有什么build议?
也许有一个Memory Leak
地方…
我对JSON解释器使用NSNull的这种疯狂的解决scheme是在NSNull上创build一个类别,在这里我定义了integerValue,floatValue,length等等。 每当你遇到另一次崩溃,添加一个新的类别。 当我有这个问题时,我想我有6或7个。
不这样做的问题是,你必须在转换的对象中findNULL – 我认为是一个PITA。
编辑:我正在使用的代码,所有在一个NSNull + JSON.m文件:
@interface NSNull (JSON) @end @implementation NSNull (JSON) - (NSUInteger)length { return 0; } - (NSInteger)integerValue { return 0; }; - (float)floatValue { return 0; }; - (NSString *)description { return @"0(NSNull)"; } - (NSArray *)componentsSeparatedByString:(NSString *)separator { return @[]; } - (id)objectForKey:(id)key { return nil; } - (BOOL)boolValue { return NO; } @end
编辑2:现在在Swift 3:
extension NSNull { func length() -> Int { return 0 } func integerValue() -> Int { return 0 } func floatValue() -> Float { return 0 }; open override var description: String { return "0(NSNull)" } func componentsSeparatedByString(separator: String) -> [AnyObject] { return [AnyObject]() } func objectForKey(key: AnyObject) -> AnyObject? { return nil } func boolValue() -> Bool { return false } }
错误信息很清楚。 NSNull
和nil
是不同的东西:
The NSNull class defines a singleton object used to represent null values in collection objects (which don't allow nil values).
如果你想检查是否authenticationToken
是NSNull
尝试: [authenticationToken isEqual: [NSNull null]]
根据David H的回答, NSNull
上的一个类如何使用ObjC的消息转发“什么也不做”来模拟发送消息到nil
时的运行时行为?
喜欢这个:
@interface NSNull (ForwardInvocation) @end @implementation NSNull (ForwardInvocation) - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [NSNull methodSignatureForSelector:@selector(description)]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { // do nothing; prevent 'unrecognized selector' crashes } @end
[NSNull methodSignatureForSelector:@selector(description)];
利用了NSNull
从NSObject
inheritance的事实,它提供了description
方法。 这满足了执行-methodSignatureForSelector:
的转发机制要求。
问题来了,因为你的方法返回一个NSNull对象。 你不能检查[authenticationToken isEqual:[NSNull null]])
因为[NSNull null]
给一个对象的实例。 所以它不同于你的对象本身。 如果你想检查你是否收到一个NSNull对象,你需要像这样检查: [authenticationToken isKindOfClass:[NSNull class]]
。