Всякий раз, когда я реализую метод в своем собственном коде, который может принимать или возвращать объекты более чем одного класса, я всегда стараюсь использовать наиболее подходящий суперкласс. Например, если бы я собирался реализовать метод, который мог бы вернуть 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, где Apple использует (id) в определенных сигнатурах методов, когда (NSObject *) будет более точным. Например, здесь метод 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) в таких случаях, но я просто не вижу этого. Что мне не хватает?