複数のクラスのオブジェクトを受け入れたり返したりできるメソッドを独自のコードに実装するときはいつでも、利用可能な最も具体的なスーパークラスを使用しようとします。たとえば、入力に応じて NSArray * または NSDictionary * を返す可能性のあるメソッドを実装する場合、そのメソッドに NSObject * の戻り型を指定します。これは最も直接的な共通のスーパークラスだからです。次に例を示します。
@interface MyParser()
- (BOOL)stringExpressesKeyValuePairs:(NSString *)string;
- (BOOL)stringExpressesAListOfEntities:(NSString *)string;
- (NSArray *)parseArrayFromString:(NSString *)string;
- (NSDictionary *)parseDictionaryFromString:(NSString *)string;
@end
@implementation MyParser
- (NSObject *)parseString:(NSString *)string {
if ([self stringExpressesKeyValuePairs:string]) {
return [self parseDictionaryFromString:string];
}
else if ([self stringExpressesAListOfEntities:string]) {
return [self parseArrayFromString:string];
}
}
// etc...
@end
Foundation やその他の API で、(NSObject *) の方が正確な場合に、Apple が特定のメソッド シグネチャで (id) を使用する多くのケースに気付きました。たとえば、NSPropertyListSerialization のメソッドは次のとおりです。
+ (id)propertyListFromData:(NSData *)data
mutabilityOption:(NSPropertyListMutabilityOptions)opt
format:(NSPropertyListFormat *)format
errorDescription:(NSString **)errorString
このメソッドから返される可能性のある型は、NSData、NSString、NSArray、NSDictionary、NSDate、および NSNumber です。(NSObject *) の戻り値の型は、(id) よりも適切な選択であると思われます。これは、呼び出し元が型キャストなしで保持のような NSObject メソッドを呼び出すことができるためです。
私は通常、公式のフレームワークによって確立されたイディオムをエミュレートしようとしますが、それらの動機を理解したいとも思っています。このような場合に Apple が (id) を使用する正当な理由があると確信していますが、私はそれを見ていません。私は何が欠けていますか?