当方法可以返回子类时,返回类型应该是什么?

时间:2011-01-06 09:45:39

标签: objective-c cocoa polymorphism

以下是一些Apple类的一些方法:

- (NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

期望所有这些方法都返回返回类型的子类是合理的。因此,返回的对象通常被分配给期望类型的变量,例如:

BCCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];

这使得编译器不高兴;一个演员解决了这个问题,但这样的演员很脏:

BCCustomTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];

但是,当返回类型为id时,可以删除此强制转换,虽然以某些类型安全为代价,导致我的代码更清晰:

BCPerson *person = [NSEntityDescription insertNewObjectForEntityForName:BCPersonEntityName inManagedObjectContext:context];

就个人而言,当返回类型为id时,我更喜欢它。 Apple是否有任何理由选择一种方法而不是另一种方法,或者仅仅是因为编写方法的开发人员的偏好?

4 个答案:

答案 0 :(得分:4)

在您描述的三个例子中,有两个不同的原则在起作用:

在第一篇文章中,Apple希望你使用一个演员作为“我知道我在做什么”的事情:当你通过一个标识符访问一个通用对象时,你最终可能会对这个类感到惊讶返回值,除非你知道你在做什么。

在后一个示例中,该方法基本上是一个工厂方法,相当于alloc init,在大多数情况下,您最好知道它是在做什么。

换句话说,回答你的问题:

对于getter的工厂方法id,与setter相同。

答案 1 :(得分:2)

我真的更喜欢演员。如果从这些方法返回id,编译器根本不会发出警告,因为它无法知道将在那里返回什么。如果您将返回值正确(并且不会转换为id),那么如果您没有收到警告,则可以确定您已正确完成。所需要的只是写一个类名。

BCCustomTableViewCell *cell = (BCCustomTableViewCell *)[tableView dequeue...];

不返回id的基本原理是你不返回任何东西,而是返回给定的类及其子类。从这个示例方法,你总是得到一个表视图单元格,你可以依赖它来响应某些方法(除非你把你的子类弄得很糟糕,就是这样)。如果你返回id,你不能依赖任何东西,加上编译器不会警告你。

编辑: 我只是指实例方法,而不是类方法。 Williham解释了这种差异。

答案 2 :(得分:1)

如果返回类型为id,那么方法定义肯定不太有用吗?您可以接收任何类型的对象,并且可能没有编译时类型检查。

最后,设置一个子类对象只会导致编译器警告,这是一个错误引起的错误导致的错误,或者误读了该文档的文档。

答案 3 :(得分:1)

转换是脏的,但让方法返回id更脏,因为潜藏在下面可能存在隐藏的危险,编译器没有机会警告你。做演员只是对编译器说'你警告过我,现在让我面临危险'。