2013/11/22

子クラスのメソッド内から親クラスのメソッドを呼ばせる必要があるときはNS_REQUIRES_SUPERを使いましょう

UIViewControllerviewDidAppear: のように、子クラスのメソッド内で親クラスのメソッドを呼ぶことを強制させたいことがあります。

このような場合に、Appleのドキュメントではその旨が書かれていたりします (例えば “If you override this method, you must call super at some point in your implementation.”) が、 うっかり忘れても警告なしでコンパイルが成功してしまいます。

NS_REQUIRES_SUPERを使うと、このようなときに警告を出してくれるようになります。

なお、詳細はClangの言語拡張を参照してください。

例えば、次のようなベースクラスとその継承クラスがあったとして、

@interface FOOBase : NSObject
-(void)someMethod;
@end

@interface FOODerieved : FOOBase
-(void)someMethod;
@end

その実装が次のようになっていてもコンパイラは何も言いません。

@implementation FOODerieved
-(void)someMethod { /* 何か重要な処理をする */ }
@end

@implementation FOODerieved
-(void)someMethod {
    // superを呼び出し忘れ
}
@end

しかし、次のようにベースクラスのメソッドでNS_REQUIRES_SUPERを宣言しておくと、

@interface FOOBase : NSObject
-(void)someMethod NS_REQUIRES_SUPER;
@end

コンパイラは次のような警告を出すようになります。

この警告を出ないようにするにはsuperのメソッドを呼ぶようにします。

@implementation FOODerieved
-(void)someMethod {
    [super someMethod];
}
@end

なお、NS_REQUIRES_SUPERは呼び出しの位置までは指定できないので、「必ずメソッドの最後で[super someMethod]させたい」というようなことを強制はできません。

また、当り前ですが孫クラスでも[super someMethod]がないと警告がでます。

ちなみに、NS_REQUIRES_SUPERはclangでの属性宣言__attribute__((objc_requires_super))と同じで単なるシンタックスシュガーです。

Appleのライブラリでこの警告が出るようになっているのかと思って、冒頭のUIViewControllerviewDidAppear:で試してみましたが警告は出ませんでした。

Appleのライブラリでこの警告が出るようになればとても嬉しいのですが…。

おわりに

NS_REQUIRES_SUPERの使いかたを簡単に紹介しました。

警告してくれるようになるだけでも大変ありがたいので、とりあえずinterfaceに追加しておくとよいでしょう。

関連リンク

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。