美文网首页面试资料收集
关于OC中self和super的笔记

关于OC中self和super的笔记

作者: 大成小栈 | 来源:发表于2021-07-07 18:27 被阅读0次

运行以下代码查看log输出,为什么NSLog的输出都Animal ?

// Person.h 文件
#import "Animal.h"

@interface Person : Animal

- (void)test;

@end


// Person.m 文件
#import "Person.h"

@implementation Person

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

@end

//// Log
[19476:618282] super---Person
[19476:618282] self---Person

1. 对象初始化的两种方式

对象初始化有两种方式:[class new] 与 [[class alloc] init]。对于后者,有分配和初始化的过程,alloc 从应用程序的虚拟地址空间上为该对象分配足够的内存,并且将新对象的引用计数加1、将对象的成员变量初始为零,init 会做真正的初使化工作,为对象的实例变量赋予合理有用的值

查看相关源码:

// new
+ new { 
    id newObject = (*_alloc)((Class)self, 0); 
    Class metaClass = self->isa; 
    if (class_getVersion(metaClass) > 1) 
    return [newObject init]; 
    else 
    return newObject; 
} 
 
// 而 alloc、init 
+ alloc { 
    return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  
} 
- init { 
    return self; 
} 

发现[class new]默认调用 alloc与init方法,多了更多的局限性。而[class alloc] init] 会更方便, 当然[class alloc] init] 的设计也是由于历史的原因。

一般不推荐使用[class new],而推荐使用[[class alloc] init]。

2. init方法中的self = [super init];

常见的重写一个类的init方法中,都会有如下写法:

- (instancetype)init {
    if (self = [super init]) {
        // Custom initialization
    }
    return self;
}
  • self是什么
    self代表着当前方法的调用者。在对象方法中,self代表当前"实例对象";在静态方法中,self则代表"类对象"。

  • super是什么
    self 和 super 是oc 提供的两个保留字,不同的是:self是类的隐藏的参数变量,指向调用当前方法的对象;super并不是隐藏的参数,它只是一个编译器指示符。(另一个隐藏参数是_cmd,代表当前类方法的selector)

  • [super init]做了什么

在一个类的方法reposition中,编译如下调用方法时,

// Class  A
- (void)reposition {  
     ...  
     [self setOrigin:someX];  
     ...  
}

编译器会将调用过程转换为:

objc_msgSend(id self,SEL _cmd, ...); //self ->实例对象

此时 self 指代实例对象,方法从对象对应 类结构的方法列表 中开始寻找,如果找不到,延继承链往 父类中寻找 。同样如果 reposition 是类方法, self 指代 A 类对象。

// Class  A
- (void)reposition {  
     ...  
     [super setOrigin:someX];  
     ...  
}

编译器会将调用过程转换为:

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

其中,第一个参数是个objc_super的结构体,

struct objc_super {
   id receiver;
   Class superClass;
};

objc_super中的成员receiver类似objc_msgSend的第一个参数 receiver;成员superClass则记录这个类的父类是什么。

当开始编译代码 [super setOrigin:someX :someY]; 时,则需要做这几个事:

  1. 构建 objc_super 的结构体,其成员变量 receiver 就是当前实例对象(self) 。而成员变量 superClass 就是指类A的 superClass。
  2. 调用 objc_msgSendSuper 的方法,将这个结构体和 setOrigin: 的 sel 传递过去。

函数里面在做的事情类似这样:从 objc_super 结构体指向的 superClass 的方法列表开始找 setOrigin 的 selector,找到后再以 objc_super->receiver 去调用这个 selector,可能也会使用 objc_msgSend 这个函数,不过此时的第一个参数 theReceiver 就是 objc_super->receiver,第二个参数是从 objc_super->superClass 中找到的 selector。

这也解释了文章,开头为什么[super class]和[self class]输出一致。
当 发送 class 消息 时不管是 self 还是 super 其消息主体依然是 self ,也就是说 self 和 super 指向的 是同一个对象。只是 查找方法的位置 区别,一个从本类,一个从本类的超类。一般情况下class方法 只有在根类 NSObject 中定义,极少情况有子类重写 class 方法,如果重写可能会不一样。
super只是个编译器符号,它可以替换成 [self class],只不过它方法是从 self 的超类开始查找。

3. 为什么要 if (self = [super init])

这样符合OC继承类初始化规范流程,[super init]递归的去self的super中调用init,直到调用根类 NSObject 中的init。即,根据各级super的init来初始化内存区域的属性,再逐级返回内存指针,直到A类中得到内存指针,赋值给self 参数。若中途初始化参数失败,则if中self为nil,可免接下来无用的初始化。

有些特殊情况是不能保证所 alloc 和 init 出来的内存是同一块内存;也有可能在父类方法初始化过程中对象空间被释放为nil,加上这样的判断是为了提高容错性,如果init成功就返回对象,否则返回nil。

4. 总结

  1. 面向对象过程中子类继承父类,就拥有了父类所有的属性和方法,一个完整的对象的初始化包括子类和父类初始化。
  2. 子类 [alloc init] 后,首先这里只有一个实例对象实体self,没有所谓的父类对象实体super。初始化过程中,子类、父类属性和方法初始化都属于子类对象的一部分,super的指针赋给self这一说法是错的,其实全部指的是该对象的初始位置。

参考文章:
https://www.cnblogs.com/damontang/p/4034890.html
https://blog.csdn.net/lin1109221208/article/details/108724965
https://opensource.apple.com/source/objc4/objc4-750.1/runtime/objc-runtime-new.h.auto.html
https://opensource.apple.com/source/objc4/objc4-750.1/runtime/objc-private.h.auto.html

相关文章

  • 关于 self 和 super 在oc 中 的疑惑 与 分析

    关于 self 和 super 在oc 中 的疑惑 与 分析

  • 关于OC中self和super的笔记

    运行以下代码查看log输出,为什么NSLog的输出都Animal ? 1. 对象初始化的两种方式 对象初始化有两种...

  • Objective-C中的self和super

    发送消息给self和super @注意:OC中的self和JAVA中的self有些不同: 1> 在动态方法中,se...

  • self和super的区别

    关于 self 和 super 在oc 中 的疑惑 与 分析 这个问题貌似很初级,但很容易让人忽略,me too ...

  • OC 中的super和self

    super和self相信大家每天都在和它们打交道,可能很多人都是按照套路来写,没怎么仔细思考过它们之间的关系,之...

  • OC中的self和super

    在面试时一般都会注重基础的,不管是对初级,中级还是高级。本人主要介绍一下在OC中最常用的两个关键字self和sup...

  • Objective-C基础学习之Self关键字

    OC提?供了两个保留字self和super OC语言中的self,就相当于C++、Java中的this指针。 要理...

  • self和super - OC

    self的应用场景: 用在类方法中使用:指代的是当前类 用在对象方法中使用:指代的是调用当前对象方法的那个对象 访...

  • OC 中self 和 super 浅析

    最近突然发现这个问题,当super通过respondsToSelector:这种方式询问是否存在方法时,这个if语...

  • oc 中 self 、super 的使用

    self 对象方法中的 self 是当前对象,可以访问属性和方法,不能访问类方法类方法中的 self 是类在代码段...

网友评论

    本文标题:关于OC中self和super的笔记

    本文链接:https://www.haomeiwen.com/subject/nysoultx.html