Objective-C中的self和super

发送消息给self和super

Objective C提供了两个保留字self和super,用于在方法定义中引用执行该方法的对象。例如,假设你定义了一个方法reposition,用来修改它所处理的某个对象的坐标,这时可以调用setOrigin::方法来完成修改。要实现这个目标,要做的工作就是将setOrigin::消息发送给一个对象,这个对象与reposition消息的接收对象是同一个。在编写代码时,你既可以使用self,也可以使用super来引用该对象,reposition方法可以是:

[cpp]  view plain copy
  1. -reposition  
  2. {  
  3.      ...  
  4.      [self setOrigin:someX :someY];  
  5.      ...  
  6. }  
也可以是:

[cpp]  view plain copy
  1. -reposition  
  2. {  
  3.      ...  
  4.      [super setOrigin:someX :someY];  
  5.      ...  
  6. }  

这里,selfe和super都引用了接收reposition消息的对象,也可以是任何其它正好被使用的对象。但是,这两个保留字是很不相同的。self是消息机制传递给每个方法的一个隐含参数,在方法的实现中可以自由使用它的本地变量,正如实例变量的名称一样。super仅在作为消息表达式中的接收者时代替self。作为接收者,这两个保留字在如何影响消息进程上有着根本不同:

  • self以常用的方式搜索方法的实现,起始于接收对象类的dispatch表。在上述例子中,它从接收repositon消息的对象类开始。
  • super是一个标记,告诉编译器在一个不同的地方搜索方法的实现。它起始于定义了super所在方法的类的超类。在上述例子中,它将从定义了repositon的类的超类开始。

只要super收到消息,编译器将为objc_msgSend替代另外一种消息机制,该消息机制直接查看定义了该类的超类,也就是发送消息给super的类的超类,而不是接收消息的对象的类。

例子:使用self和super

在使用有层级关系的三个类时,self和super之间的不同之处就很清楚了。例如,假设创建一个名为Low类的对象,Low类的超类是Mid,而Mid类的超类是High。这三个类都定义了名为negotiate的方法,分别被各个类用于自己的目的。另外,Mid定义了一个任意的方法称为makeLastingPeace,它调用了negotiate方法。

假设makeLastingPeace的实现(在Mid类中)使用了self指明了向其发送negotiate消息的对象:

[cpp]  view plain copy
  1. - makeLastingPeace  
  2. {  
  3.     [self negotiate];  
  4. ... }  

当向Low对象发送一条消息执行makeLastPeace方法,makeLastingPeace发送一条negotiate消息给相同的Low对象。这种消息机制将找到Low,也就是self所在的类中定义的negotiate。

但是,如果makeLastingPeace的实现使用super作为接收者:

[cpp]  view plain copy
  1.   
[cpp]  view plain copy
  1. - makeLastingPeace  
  2. {  
  3.     [super negotiate];  
  4. ... }  

消息机制将找到定义在High中的negotiate。它会忽略接收makeLastingPeace消息的对象的类(Low),并跳到Mid的超类,因为Mid是定义makeLastingPeace的地方,所以不会是Mid中的negotiate。

正如该例所示,super提供了一种绕过重写了其他方法的方法的一种途径。在这里,super的使用使makeLastingPeace绕过了Mid中negotiate方法,这个方法重写了High中的同名方法。

同时,它也无法获得Mid中的negotiate。这看上去似乎使一个缺陷,但在下述环境中它是有意这么做的:

  • Low类的作者有意重写了Mid的negotiate,因此Low的实例(和它的超类)将会调用重定义后的方法。但Low的设计者不希望Low对象执行被继承的方法。
  • Mid方法makeLastingPeace的作者,在发送negotiate消息给super(如第二个实现代码所示)时,有意跳过Mid的negotiate(以及任何可能在Low类中定义并继承自Mid的方法)去执行定义在High类中的版本。但makeLastingPeace的第二个实现版本的设计者希望使用High中的negotiate而非其他。

Mid中的negotiate仍然可以被使用,但它需要向Mid实例发送直接的消息。


使用super

向super发送消息可以将方法实现分发给一个以上的类。可以重写一个已有的方法来修改或将它添加到现有的方法中,仍然可以将原始的方法纳入到修改后的方法当中。

[cpp]  view plain copy
  1. - negotiate {  
  2. ...  
  3.     return [super negotiate];  
  4. }  

对于某些任务,每个继承层次结构中的类都能实现一个方法处理部分工作,然后向super传递消息让其完成剩余工作。init方法初始化新分配的实例,它就是被设计用来达成上述目的的。每个init方法负责初始化类中定义的实例变量。但在这么做之前,它会发送一条init消息给super,通知被它的超类初始化它们的实例变量。每种版本的init都遵循这个过程,因此类会按照继承的顺序来初始化实例变量。

[cpp]  view plain copy
  1. - (id)init {  
  2.     self = [super init];  
  3.     if (self) {  
  4. ... }  
  5. }  

如果想关注定义在超类中一个方法的核心功能,可以在子类中通过向super发送消息将该方法合并进来。例如,创建实例的每个类方法必须为新的对象分配存储空间,并初始化它的isa变量。分配空间的任务交给定义在NSObject类中的alloc和allocWithZone:方法去完成。如果别的类重写了这些方法(极少见的情况),它仍然可以通过发送一条消息给super来获得基本功能。


重定义self

super仅是一个面向编译器的标记,告诉编译器从哪里开始搜索方法来执行,它仅被用于消息的接收者。但self是一个变量名,用途比较多,设置可以被赋予一个新的值。

有一种趋势:在类方法的定义中实现。类方法通常不关心类对象,而是关心类的实例。例如,很多类方法都实现了实例的空间分配和初始化,并且通常会在同时建立起实例变量。在这样的方法中,向新分配的实例发送消息以及调用实例的self,这么做看上去很有吸引力,就像在一个实例方法中一样。但是这么做会报错。self和super都指向消息的接收对象,也就是接收该消息并被通知执行方法的对象。在实例方法中,self指向实例,但在类方法中,self指向的类对象。下面是个错误的例子:

[cpp]  view plain copy
  1. + (Rectangle *)rectangleOfColor:(NSColor *) color  
  2. {  
  3.     self = [[Rectangle alloc] init]; // BAD  
  4.     [self setColor:color];  
  5.     return self;  
  6. }  

为了避免这种情况,一种更好的方式是使用变量,而不是self来引用类方法种的实例:

[cpp]  view plain copy
  1. + (id)rectangleOfColor:(NSColor *)color  
  2. {  
  3.     id newInstance = [[Rectangle alloc] init]; // GOOD  
  4.     [newInstance setColor:color];  
  5.     return newInstance;  
  6. }  

实际上,比起发送alloc消息给类方法中的类这种方式来说,更好的一种方法是发送alloc给self。这种方式,如果类是子类,并且rectangleOfColor:消息是由一个子类接收的,那么返回的实例与子类是相同类型(例如,NSArray的方法array被NSMutableArray继承)。

[cpp]  view plain copy
  1. + (id)rectangleOfColor:(NSColor *)color  
  2. {  
  3.     id newInstance = [[self alloc] init]; // EXCELLENT  
  4.     [newInstance setColor:color];  
  5.     return newInstance; 
  6. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值