– :无法识别的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' 

看来authenticationTokenNULL 。 但我不明白,如果authenticationTokenNULL为什么我没有看到日志上的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 } } 

错误信息很清楚。 NSNullnil是不同的东西:

 The NSNull class defines a singleton object used to represent null values in collection objects (which don't allow nil values). 

如果你想检查是否authenticationTokenNSNull尝试: [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)]; 利用了NSNullNSObjectinheritance的事实,它提供了description方法。 这满足了执行-methodSignatureForSelector:的转发机制要求。

问题来了,因为你的方法返回一个NSNull对象。 你不能检查[authenticationToken isEqual:[NSNull null]])因为[NSNull null]给一个对象的实例。 所以它不同于你的对象本身。 如果你想检查你是否收到一个NSNull对象,你需要像这样检查: [authenticationToken isKindOfClass:[NSNull class]]