あるメソッドの返り値の型が事前に分かっている型よりも“広い”ために、わざわざキャストをしなければならないことがある。
たとえば、-[NSDocumentController sharedDocumentController]
メソッドは、通常 NSDocumentController
型のオブジェクトを返すにもかかわらず、返り値の型が id
になっている。また、 NSWindowController
の自前のサブクラスにおいて、 NSWindow
のサブクラスを扱うことが分かっているのに、 -window
メソッドの返り値の型が NSWindow
のままになっているということもあるだろう。これらのメソッドの返り値を扱うにはダウンキャストが必要になり、煩わしい:
[(NSDocumentController *)[NSDocumentController sharedDocumentController] newDocument:self];
[[(MyWindow *)[myWindowController window] myWindowMethod];
このような場合、サブクラスで同名のメソッドを宣言することで返り値の型を狭めることができる(実装は不要):
@interface MyDocumentController : NSDocumentController
// + (id)sharedDocumentController から返り値の型を狭める
+ (instancetype)sharedDocumentController;
@end
@interface MyWindowController : NSWindowController
// - (NSWindow *)window から返り値の型を狭める
- (MyWindow *)window;
@end
型を狭めることでダウンキャストが不要になる:
[[MyDocumentController sharedDocumentController] newDocument:self];
[[myWindowController window] myWindowMethod];
このように、サブクラスはスーパークラスから継承したメソッドの返り値や引数の型を変えることができる。ただし変更後の型は変更前の型のサブクラスでなければならない。
なお、既存のクラスにカテゴリを追加してメソッドの型を変えようとしても効果はない:
@interface NSApplication (TypeNarrowing)
// - (id<NSApplicationDelegate)delegate から返り値の型を狭めようとしても…
- (MyAppDelegate *)delegate;
@end
...
- (void)foo {
// 返り値の型は id<NSApplicationDelegate> のまま
[[NSApplication sharedApplication] delegate];
}