【问题标题】:-[NSNull length]: unrecognized selector sent to JSON objects-[NSNull 长度]:发送到 JSON 对象的无法识别的选择器
【发布时间】:2013-05-12 13:23:24
【问题描述】:

我正在使用最新的 SDK 开发 iOS 5.0+ 应用程序。

这段代码出现了一个非常奇怪的错误:

- (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;

有什么建议吗?

也许某处有Memory Leak...

【问题讨论】:

  • 你需要检查 if([NSNull null]== authenticationToken){NSLog(@"NULL AUTHTOKEN");}
  • 是的,您可能从 JSON 中获得了 authenticationToken,并且该值有一个 null,因此提供给您的是一个 NSNull 对象。您实际上可以使用authenticationToken == [NSNull null] 来测试这一点,因为应用程序中只有一个 NSNull 对象。
  • @HotLicks 如果您将评论添加为答案,我可以接受。

标签: ios json


【解决方案1】:

对于 JSON 解释器对 NSNull 的疯狂使用,我的解决方案是在 NSNull 上创建一个类别,我在其中定义 integerValue、floatValue、长度等 - 全部返回 0。每次您遇到另一个崩溃时,都会添加一个新类别。当我遇到这个问题时,我想我有 6 或 7 个。

不这样做的问题是您必须在转换后的对象中到处寻找 NULL - 我认为是 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

EDIT2:现在在 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 }
}

【讨论】:

  • 你先生是个天才。
  • 杰作解决方案。哇:)
  • 感谢您更新代码。它肯定会帮助很多人。
  • 这是第一个让我大笑的 SO 答案(在“每次您遇到新的崩溃...”时)
  • @DavidH 对不起,我的意思是完全免费/很棒的方式。就像哇,我从来没有想过这很酷/很古怪。
【解决方案2】:

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

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]]

【讨论】:

  • 感谢您的回答,但没有帮助。我只想知道发生了什么!我有一个NSString,然后它变为NSNull
  • @VansFannel 那你应该问这个问题。
【解决方案3】:

根据 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 的事实,NSObject 提供了description 方法。这满足了实现-methodSignatureForSelector:的转发机制要求。

【讨论】:

  • 我相信这行不通。我的解决方案所做的是返回一个键入的“无”,以便接收者可以以与“真实”答案相同的方式使用该值。请注意,在一种情况下会返回一个空数组。您还可以获得唯一的描述,因此您可以在调试时看到空值。
  • 它在我的情况下确实有效,而且感觉像是一个更通用的解决方案。谢谢!
  • @DavidH 你是对的,我的解决方案更倾向于忽略发送给 NSNull 的 objc 消息,以避免未知的选择器错误。但是对于为 JSON 解析提供默认值,您的解决方案更适合。
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 2023-03-11
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 2023-03-09
    相关资源
    最近更新 更多