Self 和Super 解释

2019-03-24  本文已影响0人  好雨知时节浩宇

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。

上一篇下一篇

猜你喜欢

热点阅读