一、了解

  1. 概念初识:

    以我们平时对代码的理解,我们都知道self代表的就是就是当前类,我们也经常用self来获取对象的实例变量或者调用实例方法。例如:self.name = @""等。而super则是父类,例如[super init]。

    代码所示:

- (instancetype)init
{
    self = [super init];
    if (self) {
          self.sonName = @"";
     }
    return self;
}

 

二. 代码实战:

      /**   JZPerson.h   **/
     @interface JZPerson : NSObject
     - (void)eat;
     @end
 
      /**   JZPerson.m   **/
     #import "JZPerson.h"
     @implementation JZPerson
     - (void)eat {
         NSLog(@"%@", [super class]);
         NSLog(@"%@", [self class]);
     }
     @end
 
     /**  main.m    **/
     int main(int argc, const char * argv[]) {
         @autoreleasepool {
             JZPerson* person = [[JZPerson alloc] init];
             [person eat];
         }
         return 0;
     }

  让我们来猜猜以上代码结果是什么?没错,结果都是JZPerson,这是为什么呢,下面我们就来看看到底是什么原因:

  我们用命令把代码转出cpp文件:clang  -rewrite-objc JZPerson.m  

1  NSLog((NSString          *)&__NSConstantStringImpl__var_folders_d0_2_bdy_qx54l4v2pksls_339m0000gn _T_JZPerson_26882c_mi_0, ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("JZPerson"))}, sel_registerName("class")));
   
2  NSLog((NSString     *)&__NSConstantStringImpl__var_folders_d0_2_bdy_qx54l4v2pksls_339m0000gn_T_JZPerson_26882c_mi_1, ((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")));

  区别就是两个函数:super调用的是class_getSuperclass,而self调用的则是objc_msgSend。

 

三、objc_msgSend与objc_msgSendSuper

  函数的用法

  id objc_msgSend(id self, SEL op, ...)  //参数1:响应接收对象的实例;参数2:执行的方法..

  objc_msgSendSuper(struct objc_super *super, SEL op, ...) //参数1:响应接收对象的实例;参数2:执行的方法..

  代码实例: 

       /**  JZPerson.h    **/ 
      @interface JZPerson : NSObject
      - (void)eat;
      @end
  
       /**  JZPerson.m    **/
      @implementation JZPerson
      - (void)eat {
          NSLog(@"%@", [self class]);
     }
     @end
 
     /**   JZSon.h JZSon继承自JZPerson    **/
     @interface JZSon : JZPerson
     - (void)eat;
     @end
 
      /**  JZSon.m    **/
     #import "JZSon.h"
     #import <objc/message.h>
     @implementation JZSon
     - (void)eat {
     
         // [super eat];
         typedef struct objc_super superStruct;
         superStruct superReceiver = {
             self,
             class_getSuperclass(object_getClass(self))
         };
         objc_msgSendSuper(&superReceiver, _cmd);
     
         // [self run];
         objc_msgSend(self, @selector(run));
     }
     - (void)run {
         NSLog(@"Run: %@", [self class]);
     }
     @end

      /**  main.m    **/
   JZSon* son = [[JZSon alloc] init];
    [son eat]; 

   以上结果你可能没猜错,就是JZSon,哈哈哈。事实证明,虽然说我们调用了[super eat]的方法,但是实际上这个父类的响应接收实例仍然是当前调用的类实例。

 

四、最后再来一个实例加深大家的理解:

    /**   JZGrandSon.h  JZGrandSon继承自上面的JZSon类  **/
    #import "JZSon.h"
    @interface JZGrandSon : JZSon
    - (void)eat;
    @end
      
    /**   JZGrandSon.m    **/
    #import "JZGrandSon.h"
    @implementation JZGrandSon
    @end

    /**   main.m    **/
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            JZGrandSon* grandSon = [[JZGrandSon alloc] init];
            [grandSon eat]; 
        }
        return 0;
    }

  此处代码执行到class_getSuperclass(object_getClass(self))将会奔溃,原因是此处调试时的结果我们可看到此处的父类是JZSon,而eat则是JZSon的实例方法,所以会执行死循环,导致奔溃。如下图所示:

 

五、总结 

  其实当我们调用了self的实例方法后,若当前类没有这个实例方法,那么将会从下至少开始查找类,直到找到合适的实例方法进行调用,而super则是从父类开始执行的这个查找方式。此处我们需要注意的是,若我们类中没有eat实例方法则会报错,毕竟没找到方法时肯定是会抛出异常。当理解了上面的objc_msgSendSuper实现方式,其它的就万变不离其宗了,哈哈哈,是不是很神奇呢?

 

    

  借鉴文章:https://www.jianshu.com/p/87fe5efe104e

 

posted on 2018-09-05 11:27  支烟慢点点  阅读(280)  评论(0)    收藏  举报