首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >假阳性respondsToSelector伴UIApplicationDelegate导致NSInvalidArgumentException

假阳性respondsToSelector伴UIApplicationDelegate导致NSInvalidArgumentException
EN

Stack Overflow用户
提问于 2011-02-14 14:05:43
回答 3查看 1.9K关注 0票数 7

简而言之,下面的代码调用超类中的现有选择器,然后给出一个NSInvalidException:

代码语言:javascript
复制
- (void)applicationWillResignActive:(UIApplication *)application {
if ([super respondsToSelector:@selector(applicationWillResignActive:)])
{
    [super applicationWillResignActive:application];
}

这就产生了以下日志异常:

  • *由于“NSInvalidArgumentException”异常终止应用程序,原因:'-aAppDelegate applicationDidEnterBackground::未识别的选择器发送到实例0x5b5d360‘

详细说明..。我有一个基本应用程序委托(来自我们的新公司库)声明为:

我有一个基本的应用程序委托类BaseAppDelegate。声明如下:

代码语言:javascript
复制
@interface CoAppDelegate : NSObject <UIApplicationDelegate> 

它执行:

代码语言:javascript
复制
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    DebugLog(@"*** ACTIVE ****");
}

它没有实现@selector(applicationWillResignActive:) --或者至少我的意思是,我没有为该方法专门编写代码。在.h或.m文件中找不到它。

我的应用程序有一个应用程序委托,从CoAppDelegate继承如下:

代码语言:javascript
复制
@interface aAppDelegate : CoAppDelegate <UIApplicationDelegate>

我将上述两种方法都实现为:

代码语言:javascript
复制
- (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会给出“是”?我错过了什么微妙的小东西?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-03 15:28:58

而不是[super class],您应该使用[self superclass]

代码语言:javascript
复制
[[self superclass] instancesRespondToSelector:@selector(method)]
票数 9
EN

Stack Overflow用户

发布于 2011-02-14 14:13:14

您应该使用instancesRespondToSelector:,原因如下在文档中说明

不能通过使用respondsToSelector:关键字向对象发送super来测试对象是否继承了超类的方法。 该方法仍将测试整个对象,而不仅仅是超类的实现。因此,将respondsToSelector:发送到super等同于将其发送到self。相反,您必须直接在对象的超类上调用NSObject类方法instancesRespondToSelector:

子类的代码应该如下所示:

代码语言:javascript
复制
- (void)applicationWillResignActive:(UIApplication *)application {
    if ([[self superclass] instancesRespondToSelector:_cmd])
    {
        [super applicationWillResignActive:application];
    }
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    if ([[self superclass] instancesRespondToSelector:_cmd])
    {   
        [super applicationDidBecomeActive:application];
    }
}
票数 9
EN

Stack Overflow用户

发布于 2014-07-04 08:38:26

代码语言:javascript
复制
[[self superclass] instancesRespondToSelector:<selector>];

在某些特殊情况下可能产生不期望的结果。最好是显式地声明类名,而不是self:

代码语言:javascript
复制
[[<ClassName> superclass] instancesRespondToSelector:<selector>];

解释:

举个例子:

代码语言:javascript
复制
@protocol MyProtocol <NSObject>
@optional
- (void)foo;
- (void)bar;
@end

@interface A : NSObject <MyProtocol>
@end

@implementation A 
- (void)foo {
     //Do sth
}
@end

@interface B : A
@end

@implementation B
- (void)bar {
    //B may not know which methods of MyProtocol A implements, so it checks
    if ([[self superclass] instancesRespondToSelector:@selector(bar)]) {
        [super bar];
    }
    //Do sth
}
@end

@interface C : B
@end

@implementation C
@end

那么,想象一下下面的代码:

代码语言:javascript
复制
C *c = [C new];
[c bar];

这个密码..。撞车!为什么?让我们深入研究在C实例'c‘上调用bar方法时发生了什么。自我超阶级回来..。B,因为self是C的实例,所以B实例会回复到bar,所以输入if的主体。但是,超级栏试图从B的角度调用超级实现,所以尝试调用A上的bar,这会导致崩溃!

这就是为什么我建议用精确的B超类取代自我超类-这解决了这个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4993069

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档