super 學習筆記

super是一個編譯指示器,僅僅是給編譯器看的,不是一個指針。只要編譯器看到super這個標誌,就會讓當前對象調用父類的方法,但是方法的調用者還是當前對象本身。

// ----- Model.h -----
#import <Foundation/Foundation.h>

@interface Model : NSObject

//僅僅開放一個方法,不實現
- (void)test;

@end

// ----- Model.m -----
#import "Model.h"

@implementation Model

@end

// ----- SubModel.h -----
#import "Model.h"

// 繼承自Model
@interface SubModel : Model  

@end

// ----- SubModel.m -----
#import "SubModel.h"

@implementation SubModel

// SubModel繼承自Model,調用父類定義的方法test
- (void)test
{
    // class: 獲取class方法調用者的類
    // superclass: 獲取superclass方法調用者的父類

    // super: 僅僅是一個編譯指示器,就是給編譯器看的,不是一個指針
    // 本質:只要編譯器看到super這個標誌,就會讓當前對象去調用父類方法,本質還是當前對象在調用

    NSLog(@"self class:%@",[self class]);
    NSLog(@"self superclass:%@",[self superclass]);
    NSLog(@"super class:%@",[super class]);
    NSLog(@"super superclass:%@",[super superclass]);
}

@end
// ------ ViewController.m ------
- (void)viewDidLoad {
    [super viewDidLoad];

    SubModel *subModel = [[SubModel alloc] init];
    [subModel test];
}

調用結果

調用結果

假如在SubModel中調用父類的test方法,將4個Log放入父類的test方法中,輸出結果還是和上例一樣。因爲self還是SubModel對象,它僅僅只是調用了父類的方法。

// ------ SubModel.m ------
// SubModel繼承自Model,調用父類定義的方法test
- (void)test
{
    // class: 獲取class方法調用者的類
    // superclass: 獲取superclass方法調用者的父類

    // super: 僅僅是一個編譯指示器,就是給編譯器看的,不是一個指針
    // 本質:只要編譯器看到super這個標誌,就會讓當前對象去調用父類方法,本質還是當前對象在調用

//    NSLog(@"self class:%@",[self class]);
//    NSLog(@"self superclass:%@",[self superclass]);
//    NSLog(@"super class:%@",[super class]);
//    NSLog(@"super superclass:%@",[super superclass]);

    //調用父類的test方法
    [super test];
}
// ------ Model.m ------
- (void)test
{
    //結果還是 SubModel Model SubModel Model, 雖然調用的是父類Model的test方法,self還是SubModel對象。

    NSLog(@"self class:%@",[self class]);
    NSLog(@"self superclass:%@",[self superclass]);
    NSLog(@"super class:%@",[super class]);
    NSLog(@"super superclass:%@",[super superclass]);
}

調用結果

調用結果

super底層代碼

  • 新建一個命令行項目(Command Line Tool)
//main.m

#import <Foundation/Foundation.h>

@interface Model : NSObject

@end

@implementation Model

- (instancetype)init
{
    self = [super init];
    return self;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
    }
    return 0;
}
  • 打開終端,cd進包含main.m文件的文件夾(注意,這裏是文件夾!!!),執行命令 clang -rewrite-objc main.m,在該文件夾下會多出一個.cpp後綴的文件,打開該文件,cmd+F,搜索@autoreleasepool,找到底層實現代碼
// main.cpp
#ifndef _REWRITER_typedef_Model
#define _REWRITER_typedef_Model
typedef struct objc_object Model;
typedef struct {} _objc_exc_Model;
#endif

struct Model_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
};


/* @end */


// @implementation Model

static instancetype _I_Model_init(Model * self, SEL _cmd) {
    // 這裏就是我們要找的底層代碼 
    self = ((Model *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Model"))}, sel_registerName("init"));
    return self;
}

// @end

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_y5_y2q0fd790k900f9k1lxkz7ww0000gn_T_main_0aa3fc_mi_0);
    }
    return 0;
}
  • super的底層實現代碼
((Model *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Model"))}, sel_registerName("init"))

// 將強制類型轉換全部刪除掉
objc_msgSendSuper({self,class_getSuperclass(objc_getClass("Model"))},sel_registerName("init"))

objc_msgSendSuper(<#struct objc_super *super#>, <#SEL op, …#>) 第一個參數是個objc_super結構體,第二個參數是SEL

// receiver是指類的實例,super_class則是指該實例的父類

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained Class class;
#else
    __unsafe_unretained Class super_class;
#endif
    /* super_class is the first class to search */
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章