Self 和Super 解释

1、self 和 super的官方解释

self
Whenever you’re writing a method implementation, you have access to an important hidden value, self. Conceptually, self is a way to refer to “the object that’s received this message.” It’s apointer, just like the greeting value above, and can be used to call a method on the current receiving object.

super
super is a flag that tells the compiler to search for the method implementation in a very different place. It begins in the superclass of the class that defines the method where super appears.

结论:

self : 是一个隐私参数,熟悉C的都知道,他和 _cmd构成方法的参数,self是动态的;执行时调用RT的objc_msgSend();

super : 是个编译器的指令符号,只是告诉编译器在执行的时候,去调谁的方法.super是编译的;执行时调用RT的objc_msgSendSuper();

self 调用的是本类的方法,super调用的是父类中的方法。

2、self 和 super的底层实现原理:

将下面的代码clang后,我们来看一下这两句代码到底是怎样转化并执行的:

- (void)test{
    [self class];
    [super class];
}

编译后的代码:

static void _I_Man_test(Man * self, SEL _cmd) {
    ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"));//[self class]调用
    ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Man"))}, sel_registerName("class"));//[super class]调用
}

经过clang后,编译为上面的代码,简化一下可以看到:[self class]实际上转换成为objc_msgSend()来发送消息。 [super class]实际上转换为objc_msgSendSuper()来发送消息。

分别看下objc_msgSend()和objc_msgSendSuper()的定义。

1)objc_msgSend()函数声明如下:

id objc_msgSend(id theReceiver, SEL theSelector, ...)

theReceiver:消息接受者,theSelector:要调用的方法,后面为可变参数。其中self就是这里的theReceiver参数。

2)objc_msgSendSuper()函数声明如下:

id objc_msgSendSuper(struct objc_super *super, SEL op, ...)

第一个参数是是一个objc_super 结构体,不再是一个id类型的对象,后面的参数跟objc_msgSend相同,分别是selector和可选参数。

3) 我们再来看一下struct objc_super定义:

/// Specifies the superclass of an instance. 
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__ //这里采用宏判断,现在是OBJC2.0,所以不会走这个if。
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
};

我们可以看到结构体主要是由reviceiver和super_class构成的。而receiver就是一个类的实例对象(也就是self),super_class则是指向父类。即:首先从super->super_class指向的父类的方法中查找对应的selector,找到后再使用 super->receiver 调用对应的selector。

了解了底层实现后,我们也就清楚为什么 [self class][super class]返回值是相同的。
再来看一个例子:

@implementation Person

- (void)personBaseMethod {
    NSLog(@"%@",[self class]);
}

@end


@implementation Student

- (void)personBaseMethod {
    NSLog(@"%@",[self class]);
    NSLog(@"========");
    [super personBaseMethod];
}

//调用 Student中的personBaseMethod 打印结果如下:
Student
========
Student

self指向的是当前Student的实例对象,而super则是:先去父类的方法列表中找到personBaseMethod,然后给self(也就是Student的实例对象)发消息。由self对象来执行父类personBaseMethod这个方法体中的[self class]。 所以最终还是由self来执行sel_registerName("class") 这个selector

关于objc_msgSend函数的实现我们是看不到的,它的实现是以汇编语言完成的。这里有一篇博客,作者根据机器码反推出了实现。

2、为什么要有 self = [super init];

init方法在初始化失败后会返回nil,OC中关于 init 的约定有一个重要部分:可以通过返回 nil 来告诉调用者,初始化失败了;(初始化可能会因为各种原因失败,比如一个输入的格式错误了,或者另一个需要的对象初始化失败了。)
这样我们就能理解为什么总是需要调用 self = [super init]。
原因就是:1、如果父类说初始化自己的时候失败了,那么必须假定当前的self实例正处于一个不稳定的状态,因此在你的实现里不要继续你自己的初始化并且也返回 nil。如果不这样做,你可能会操作一个不可用的对象,它的行为是不可预测的,最终可能会导致你的程序崩溃。
2、alloc后返回的是一个有效但初始化的对象,init负责初始化对象,,使对象处于可用状态。所以沿着继承链往上调用init犯法,使得对象的各级父类都能够完成初始化操作,并为其实例变量赋予合理的值。

3、关于OC的alloc 和 init(摘自:OC禅与艺术 )

我们常常写 [[NSObject alloc] init] 这样的代码,从而淡化了 alloc 和 init 的区别。Objective-C 的这个特性叫做 两步创建

这意味着申请分配内存和初始化被分离成两步,alloc 和 init。

 1、 alloc 负责创建对象,这个过程包括分配足够的内存来保存对象,写入 isa 指针,初始化引用计数,以及重置所有实例变量。
 2、init 负责初始化对象,这意味着使对象处于可用状态。这通常意味着为对象的实例变量赋予合理有用的值。

alloc 方法将返回一个有效的未初始化的对象实例。每一个对这个实例发送的消息会被转换成一次 objc_msgSend() 函数的调用,形参 self 的实参是 alloc 返回的指针;这样 self 在所有方法的作用域内都能够被访问。

按照惯例,为了完成两步创建,新创建的实例第一个被调用的方法将是 init 方法。注意,NSObject 在实现 init 时,只是简单的返回了 self。

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

推荐阅读更多精彩内容

  • 今天是房东蒋老头这个月第四次敲响306的房门,房租已经拖欠两个月了,蒋老头下定决心今天要敲开306的门,告诉房客自...
    九丑_阅读 867评论 7 16
  • 项目中的更新下载,图片拍照,如果是7.0以下,没有发现任何异常,但是到了7.0以上,你会发现,你大爷已经不是以前的...
    大川的川阅读 2,261评论 0 0
  • 2019.2.25 今天多云,星期一 昨天晚上坐火车10+个小时,今天早晨回到家,整理一下卫生和带...
    志枚阅读 68评论 0 3
  • 今天是年初二。除夕那天,从下午看到哈迪的文章之后,我决定给朋友们一个个地发祝福语。 其实中午开始已经陆续收到一些祝...
    saiyonana阅读 163评论 0 0