美文网首页面试资料收集
关于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

    相关文章

      网友评论

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

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