Objective-C中的self和super

发送消息给self和super

@注意:OC中的self和JAVA中的self有些不同:

1> 在动态方法中,self代表着"对象"

2> 在静态方法中,self代表着"类"

3> 万变不离其宗,记住一句话就行了:self代表着当前方法的调用者

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

[cpp]view plaincopy

-reposition

{

...

[self setOrigin:someX :someY];

...

}

也可以是:

[cpp]view plaincopy

-reposition

{

...

[super setOrigin:someX :someY];

...

}

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

1:self是类的隐藏的参数,指向当前调用方法的类,另一个隐藏参数是_cmd,代表当前类方法的selector。

2: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 plaincopy

- makeLastingPeace

{

[self negotiate];

... }

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

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

[cpp]view plaincopy

[cpp]view plaincopy

- makeLastingPeace

{

[super negotiate];

... }

消息机制将找到定义在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 plaincopy

- negotiate {

...

return[super negotiate];

}

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

[cpp]view plaincopy

- (id)init {

self = [super init];

if(self) {

... }

}

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

重定义self

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

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

[cpp]view plaincopy

+ (Rectangle *)rectangleOfColor:(NSColor *) color

{

self = [[Rectangle alloc] init];// BAD

[self setColor:color];

returnself;

}

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

[cpp]view plaincopy

+ (id)rectangleOfColor:(NSColor *)color

{

id newInstance = [[Rectangle alloc] init];// GOOD

[newInstance setColor:color];

returnnewInstance;

}

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

@不过,我觉得这里最好写成---- id newInstance = [[[self class] alloc ] init]

[cpp]view plaincopy

+ (id)rectangleOfColor:(NSColor *)color

{

id newInstance = [[self alloc] init];// EXCELLENT

[newInstance setColor:color];

returnnewInstance;

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容