在什么条件下,instancesRespondToSelector:返回true,但是performSelector:抛出异常

时间:2013-04-09 07:34:16

标签: ios objective-c exception unrecognized-selector

我的代码分布在一个如下所示的库中:

if ([[NSString class] instancesRespondToSelector: @selector(JSONValue)]) {
  NSString *jsonString = [[[NSString alloc] initWithData: jsonData encoding: NSUTF8StringEncoding] autorelease];
  dict = [jsonString performSelector: @selector(JSONValue)];
}

由于某种原因,调用-[__NSCFString JSONValue]: unrecognized selector sent to instance方法时会抛出performSelector:异常。这是在我编写的库中分发的代码,但我自己无法重现或调试它。相反,第三方报告此问题。在使用instancesRespondToSelector:实际调用方法时performSelector:可以在什么条件下抛出异常?

修改 有一种情况可以解释为什么会发生这种情况,但这没有意义。如果开发人员要做这样的事情:

@implementation NSString (OurHappyCategory)

+ (BOOL)instancesRespondToSelector:(SEL)aSelector
{
  return YES;
}

@end

它会解释为什么代码正在执行,但它当然是非常糟糕的事情。有没有办法解决这个问题?

5 个答案:

答案 0 :(得分:7)

NSString基本上是一个class cluster,会带来各种各样的复杂情况......你实际上需要询问实例是否响应选择器。

NSString *jsonString = [[[NSString alloc] initWithData: jsonData encoding: NSUTF8StringEncoding] autorelease];
if ([jsonString respondsToSelector: @selector(JSONValue)]) {
  dict = [jsonString performSelector: @selector(JSONValue)];
}

但你的问题可能与编译或链接扩展有关...如果在库中添加了类别,那么你需要在-ObjC链接器标记中撒上。

修改
我一直在努力重现这个问题......我无法...... 你有更多的信息.​​.例如是故障只发生在模拟器上,还是只发生在设备上,iOS 4.x,GNU链接器与LLDB的链接器,ABI /运行时差异?

答案 1 :(得分:4)

我猜你没有以正确的方式导入第三方库。通常这个方法被添加为NSString的类别,在我看来我可以看到.h文件但是.m没有被编译。你可以在xcode目标 - >构建阶段 - >编译源代码中查看它。或者检查一下Project中是否有这个标志 - > Build Settings - > Other linker flag = -all_load

答案 2 :(得分:4)

异常不直接来自Objective-C运行时,以响应发送实例无法识别的消息。它来自-[NSObject doesNotRecognizeSelector:],在各种方法查找和转发机制结束时调用。

但是,任何事情都可以在需要时调用-doesNotRecognizeSelector:。类可以通过覆盖它并使覆盖只调用-doesNotRecognizeSelector:来“拒绝”继承的方法。作为documented,尽管-respondsToSelector:(和+instancesRespondToSelector:)返回YES,但这会导致您看到异常。

我无法告诉你为什么__NSCFString在最终用户的情况下这样做。使用您的库的应用程序是否使用类别或方法调整以修改该类的方法?

此外,您的日志记录是否显示异常中的实际堆栈跟踪捕获?这可能是提供信息的。

答案 3 :(得分:0)

有一种奇怪的可能性:可能是performSelector本身在不同的链接加载环境中以某种方式执行而不是代码的其余部分。但不完全(甚至大致)确定如何发生这种情况。

答案 4 :(得分:0)

确保没有人在调整功能