每当我实现我自己的代码的方法,可以接受或返回多于一个类的对象,我总是尝试使用可用的最具体的超类。例如,如果我要实现可能返回一个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

我注意到在基金会并在苹果使用(ID)的某些方法签名其他API很多情况下(NSObject的*)会更精确。例如,这里的NSPropertyListSerialization的方法:

+ (id)propertyListFromData:(NSData *)data 
          mutabilityOption:(NSPropertyListMutabilityOptions)opt 
                    format:(NSPropertyListFormat *)format 
          errorDescription:(NSString **)errorString

此方法的可能的返回类型是NSData的,的NSString,NSArray的,NSDictionary中,的NSDate,和NSNumber的。在我看来,是的(NSObject的*)返回类型会比(ID),一个更好的选择,因为主叫方然后能调用NSObject的方法,如保留无型铸造。

我一般都尽量模仿由官方建立的框架成语,但我也想明白了什么激励他们。我敢肯定,苹果公司已经在这样的情况下使用(ID)的一些正当的理由,但我只是没有看到它。我缺少什么?

有帮助吗?

解决方案

使用ID告诉编译器将是未知类型的对象。使用NSObject的编译器会那么希望你能只使用可用于NSObject的消息是。所以...如果你知道返回一个数组,它铸成ID,您可以拨打objectAtIndex:没有编译器警告。而与NSObject中的铸造返回时,你会得到警告。

其他提示

为什么(ID)中的方法声明使用的原因是双重的:

(1)的方法,可采取或返回任何类型。 NSArray的包含任何随机对象,因此,objectAtIndex:将返回任何无规型的对象。铸造它NSObject*id <NSObject>将有两个原因是不正确的;第一,一个阵列可以包含非NSObject的子类,只要它们实现了一定小的一套方法,其次,一个特定的返回类型将需要铸件。

(2)目标C不支持协变声明。考虑:

@interface NSArray:NSObject
+ (id) array;
@end

现在,你可以叫上都+arrayNSArray NSMutableArray。前者返回一个不可变的阵列,后者是可变数组。由于Objective-C的缺乏协声明支持,如果上面的方法声明为返回(NSArray*),子类方法的客户将不得不转换为`(NSMutableArray的*)。丑陋的,脆弱的,而且容易出错。因此,使用一般类型是,通常,最简单的解决方案。

所以...如果你宣称返回一个特定的类的实例的方法,明确的类型转换。如果您声明将被覆盖的方法和覆盖可能会返回一个子类的的,它返回一个子类将暴露给客户的事实,然后用(id)

<击>无需提交错误 - 有几个已经


请注意ObjC现在具有穿过instancetype关键字限于协方支撑。

即。 NSArray的+阵列的方法,现在可以声明为:

+ (instancetype) array;

和编译器会对待[NSMutableArray array]为返回一个NSMutableArray*[NSArray array]将被视为返回NSArray*

您已经可以拨打-retain对ID类型的指针,而无需进行转换。如果您使用的是具体的超类型,你必须每次调用子类的方法,以避免编译器警告时间转换指针。使用ID,因此编译器不会发出警告,并更好地表明你的意图。

(ID)也经常返回,以便使物体被更容易地创建子类。例如,在初始化和方便的方法,返回(ID)指任何亚类不具有覆盖超类的方法,除非有特定的理由这样做。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top