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が表示されることを期待しているときにrespondsToSelectorがYESを返すのはなぜですか?私が見逃している小さな微妙なことは何ですか?

4

3 に答える 3

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 に答える
9

代わりに[super class]使用する必要があります[self superclass]

[[self superclass] instancesRespondToSelector:@selector(method)]
于 2011-10-03T15:28:58.630 に答える
0
[[self superclass] instancesRespondToSelector:<selector>];

特別な場合には、望ましくない結果が生じる可能性があります。自分自身ではなく、クラス名を明示的に指定することをお勧めします。

[[<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メソッドを呼び出すときに何が起こっているのかを調べてみましょう。[selfsuperclass]は...Bを返します。selfはCのインスタンスであるためです。もちろん、Bインスタンスはbarに応答するため、ifの本体が入力されます。ただし、[スーパーバー]はBの観点からスーパー実装を呼び出そうとするため、Aでバーを呼び出そうとするとクラッシュします。

そのため、[自己スーパークラス]を正確な[Bスーパークラス]に置き換えることをお勧めします。これで問題が解決します。

于 2014-07-04T08:38:26.410 に答える