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。
网友评论