UIApplicationDelegate 误报 respondsToSelector 导致 NSInvalidArgumentException
简而言之,以下代码调用超类中的现有选择器,然后给出 NSInvalidException:
- (void)applicationWillResignActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationWillResignActive:)])
{
[super applicationWillResignActive:application];
}
这给出了以下日志异常:
- *** 由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序,原因: '-[aAppDelegate applicationDidEnterBackground:] :无法识别的选择器发送到实例 0x5b5d360'
详细说明...我有一个基本应用程序委托(来自我们的新公司库)声明为:
我有一个基本应用程序委托类 BaseAppDelegate。它被声明为:
@interface CoAppDelegate : NSObject <UIApplicationDelegate>
它实现:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
DebugLog(@"*** ACTIVE ****");
}
它不实现 @selector(applicationWillResignActive:) - 或者至少我的意思是我没有专门为该方法编写代码。在 .h 或 .m 文件中找不到它。
我的应用程序有一个从 CoAppDelegate 继承的应用程序委托:
@interface aAppDelegate : CoAppDelegate <UIApplicationDelegate>
我将上述两种方法实现为:
- (void)applicationWillResignActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationWillResignActive:)])
{
[super applicationWillResignActive:application];
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationDidBecomeActive:)])
{
[super applicationDidBecomeActive:application];
}
}
当应用程序启动时,我得到调试输出“*** ACTIVE ****” - 正如它应该的那样。
当我将应用程序发送到后台时,我得到 NSInvalidArgumentException ,指出响应者不存在 - 并且它不存在,因此这是抛出的正确异常。
我需要知道的是,为什么当我期望看到“否”时,respondsToSelector 却给出“是”?我缺少的微妙的小东西是什么?
In short, the following code calls an existing selector in the super class, and then gives an NSInvalidException:
- (void)applicationWillResignActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationWillResignActive:)])
{
[super applicationWillResignActive:application];
}
This gives the following log exception:
- *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[aAppDelegate applicationDidEnterBackground:]: unrecognized selector sent to instance 0x5b5d360'
To elaborate... I have a base application delegate (from our new company library) declared as:
I have a base application delegate class, BaseAppDelegate. It is declared as:
@interface CoAppDelegate : NSObject <UIApplicationDelegate>
It implements:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
DebugLog(@"*** ACTIVE ****");
}
It does not implement @selector(applicationWillResignActive:) - or at least what I mean is that I have not specifically written out code for that method. It can't be found in the .h or .m file.
My app has an app delegate that inherits from CoAppDelegate as:
@interface aAppDelegate : CoAppDelegate <UIApplicationDelegate>
I implement both of the above methods as:
- (void)applicationWillResignActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationWillResignActive:)])
{
[super applicationWillResignActive:application];
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationDidBecomeActive:)])
{
[super applicationDidBecomeActive:application];
}
}
When the app launches, I get the debug output "*** ACTIVE ****" - as it should.
When I send my app to the background I get that NSInvalidArgumentException stating that the responder does not exist - and it does not exist, so this is the correct exception to throw.
What I need to know is WHY does respondsToSelector give a YES when I am expecting to see a NO? What is the little subtle thing that I am missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您应该使用
[self superclass]
而不是[super class]
:Instead of
[super class]
you should use[self superclass]
:您应该使用
instancesRespondToSelector:
原因如下 文档:您的子类的代码应如下所示:
You should use
instancesRespondToSelector:
for the following reason stated in the documentation:Your subclass' code should look like this:
在某些特殊情况下可能会产生不希望的结果。最好显式地声明类名而不是 self:
说明:
考虑示例:
想象一下以下代码:
此代码...崩溃!为什么?让我们深入研究一下在 C 实例“c”上调用 bar 方法时发生了什么。 [self superclass] 返回... B,因为self是C的实例。当然,B实例响应bar,所以进入if的主体。然而,[super bar] 尝试从 B 的角度调用 super 实现,因此尝试在 A 上调用 bar,这会导致崩溃!
这就是为什么我建议用精确的 [B 超类] 替换 [self superclass] - 这可以解决问题。
may produces undesired results in some special cases. It is better to explicitly state class name instead of self:
Explanation:
Consider example:
Imagine then following code:
This code ... crashes! Why? Let's dig through what's going on when calling bar method on C instance 'c'. [self superclass] returns... B, since self is instance of C. Of course, B instances reponds to bar, so the body of if is entered. However, [super bar] tries to call super implementation from B's perspective, so tries to call bar on A, which results in crash!
That's why I suggest to replace [self superclass] with precise [B superclass] - which solves the problem.