7

简而言之,以下代码调用超类中现有的选择器,然后给出一个 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 说明响应者不存在 - 而且它不存在,所以这是要抛出的正确异常。

我需要知道的是,为什么当我期望看到 NO 时,responsToSelector 会给出 YES?我错过了什么微妙的小东西?

4

3 回答 3

9

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

[[self superclass] instancesRespondToSelector:@selector(method)]
于 2011-10-03T15:28:58.630 回答
9

您应该使用文档instancesRespondToSelector:中所述的以下原因:

您无法通过使用关键字发送respondsToSelector:到对象来测试对象是否从其超类继承方法。super

此方法仍将测试整个对象,而不仅仅是超类的实现。因此,发送respondsToSelector:super等同于将其发送至self。相反,您必须直接在对象的超类上调用NSObject类方法。instancesRespondToSelector:

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

- (void)applicationWillResignActive:(UIApplication *)application {
    if ([[self superclass] instancesRespondToSelector:_cmd])
    {
        [super applicationWillResignActive:application];
    }
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    if ([[self superclass] instancesRespondToSelector:_cmd])
    {   
        [super applicationDidBecomeActive:application];
    }
}
于 2011-02-14T14:13:14.637 回答
0
[[self superclass] instancesRespondToSelector:<selector>];

在某些特殊情况下可能会产生不希望的结果。最好明确声明类名而不是 self:

[[<ClassName> superclass] instancesRespondToSelector:<selector>];

解释:

考虑示例:

@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

想象一下下面的代码:

C *c = [C new];
[c bar];

此代码...崩溃!为什么?让我们深入了解在 C 实例“c”上调用 bar 方法时发生了什么。[self 超类] 返回... B,因为 self 是 C 的实例。当然,B 实例响应 bar,所以进入 if 的主体。但是,[super bar] 尝试从 B 的角度调用 super 实现,因此尝试在 A 上调用 bar,这会导致崩溃!

这就是为什么我建议用精确的 [B superclass] 替换 [self superclass] - 这可以解决问题。

于 2014-07-04T08:38:26.410 回答