使用[self class]有什么作用?

19

这段代码是否正确

@implementation Vehicle
+(id) vehicleWithColor:(NSColor*)color {
    id newInstance = [[[self class] alloc] init]; // PERFECT, the class is // dynamically identified
    [newInstance setColor:color];
    return [newInstance autorelease];
}
@end

为什么要使用[self class]?

我曾认为在静态方法(使用+号定义的方法)中,self已经指向了该类。


2
我也不认为这是必要的。 - zneak
2个回答

20

你是对的:在一个类方法中,[self class] 是不必要的(在Objective-C中通常称为类方法而不是“静态”方法),因为self已经是一个类,并且[self class]返回它自己。

但这变得更加有趣了。在Objective-C中,类对象在技术上是元类的实例。因此,在一个类方法中,[self class]应该返回元类而不是类本身。但是出于实际目的,Objective-C将元类隐藏起来并特殊处理这种情况。

关于这个主题的一些好读物:


类是元类。不是元类的另一个类是实例。嗯... 我自己也有点困惑。我先读一下。 - user4951
元类是某个超类的实例。从某种意义上说,该实例即为类。[self class]应该返回你指的元类超类吗?但它仍然只是self对吧? - user4951
啊,我明白了,[self class] 应该返回元类。但它没有,它返回自身。有趣。 - user4951
@Jim - 是的,你说对了。很难解释元类,并且(根据我的经验)实际上很少有用,但是玩弄它可能会很有趣。Common Lisp和Python具有更易于访问和配置的元对象协议。(参见http://en.wikipedia.org/wiki/Metaclass) - Daniel Dickison
因此,在类方法中,[self class] 应该返回元类而不是类本身。不是的。它调用了 NSObject 中定义的 +class 类方法,而不是 -class 实例方法。对于类对象,+class 会覆盖 -class+class 只是简单地返回被调用的对象,而不是对象的类。 - user102008
显示剩余5条评论

19

这是为了支持子类化。如果像 [[Vehicle alloc] init] 这样硬编码了类名,那么 Vehicle 的一个子类就必须覆盖 +vehicleWithColor: 方法来使其正常工作。使用 [self class],你可以创建一个 HarleyDavidson 子类,[HarleyDavidson vehicleWithColor:[NSColor blackColor]] 就会自动地执行正确的操作,创建 HarleyDavidson 实例而不是 Vehicle 实例。

(编辑:)

请参考 Joe 下面的评论,关于类方法中的 self[self class] - 在类方法中,两者没有区别。但确实存在一种情况。类可以响应在根类中定义的实例方法,例如 NSObject 协议中定义的 -class 方法本身就是这样一个实例方法。因此,如果扩展了一个根类(例如 NSObject)并添加了一个实例方法,则该方法应始终使用 [self class] 如果需要引用其自己的 Class 对象。


3
另外需要注意的是 [self class] 可以工作,但在静态方法中使用 self 就已经代表了类本身。因此,直接使用 [[self alloc] init] 会更为简便。 - Joe
1
@Joe - 再次阅读问题,我认为self[self class]可能是吉姆询问的内容,而不是硬编码的类名。 - Sherm Pendley
1
你说得对,我想我是通过评论你的帖子来回答他的 :) 拿着你的+4跑吧! - Joe
对于仍然对Daniel的话感到困惑的人,请自行尝试。在实例方法中使用self来调用类方法(同一类的类方法,否则你就不会使用self了)。你会得到一个错误。但是在类方法中使用self.class来调用同一类的类方法是不必要的。Self将能够正常工作。 - pnizzle
请注意,您还可以将[[self class] alloc] init...]写成[[self.class alloc] init...]的形式,因为-[NSObject class]实际上是NSObject的一个属性。Objective-C不在乎您是否对不带参数的方法使用属性表示法,在这种情况下(以及许多其他情况下),假装class是一个属性在语法上更加清晰。有趣的是,superclass 确实是NSObject的官方属性。 - Todd Lehman
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接