OC中Runtime super關鍵字

在平時的開發過程中,我們經常會執行[super xxx]來調用父類的方法,但是我們很少會去關心super關鍵字的底層是如何實現的,接下來我們來看下super關鍵字底層實現原理,我們新建一個工程,然后創建Person類和Student類,Student類繼承自Person類,示例代碼如下:

Person

@interface Person : NSObject

- (void)run;
@end


@implementation Person

- (void)run {
    NSLog(@"%s", __func__);
}
@end

Student

@interface Student : Person

@end


@implementation Student

- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"%@", [self class]); // Student
        NSLog(@"%@", [self superclass]); // Person
        
        NSLog(@"%@", [super class]); // Student
        NSLog(@"%@", [super superclass]); // Person
    }
    return self;
}

- (void)run {
    [super run];
    
    NSLog(@"%s", __func__);
}
@end

main函數:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Student *stu = [[Student alloc] init];
        [stu run];
    }
    return 0;
}

接下來我們執行命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 Student.mStudent.m文件轉換為底層c++文件,轉換為底層的run方法代碼如下:

static void _I_Student_run(Student * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));

    NSLog((NSString *)&__NSConstantStringImpl__var_folders_lr_81gwkh751xzddx_ffhhb5_0m0000gn_T_Student_18b3ae_mi_0, __func__);
}

我們將Studnnt類的run方法進行簡化如下:

- (void)run {
    [super run];
    
    /**
     結構體objc_super包含兩個成員:
     self:消息接收者(receiver)
     class_getSuperclass(objc_getClass("Student")):消息接收者的父類(super_class)
     */
    struct objc_super superStruct = {
        self,
        class_getSuperclass(objc_getClass("Student"))
    };
    
    objc_msgSendSuper(superStruct, sel_registerName("run"));
    
    NSLog(@"%s", __func__);
}

我們發現當我們在run函數中執行[super run]后,最終底層轉換為objc_msgSendSuper()消息發送,我們通過底層源碼看下objc_msgSendSuper函數的定義,查找路徑objc4 -> message.h -> objc_msgSendSuper,具體底層函數定義如下:

/**
 * Sends a message with a simple return value to the superclass of an instance of a class.
 *
 * @param super A pointer to an \c objc_super data structure. Pass values identifying the
 *  context the message was sent to, including the instance of the class that is to receive the
 *  message and the superclass at which to start searching for the method implementation.
 * @param op A pointer of type SEL. Pass the selector of the method that will handle the message.
 * @param ...
 *   A variable argument list containing the arguments to the method.
 *
 * @return The return value of the method identified by \e op.
 *
 * @see objc_msgSend
 */
 
OBJC_EXPORT id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);

我們從源碼objc_msgSendSuper函數定義可以看到,函數接受兩個參數

  • objc_super
  • SEL

我們再來看下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__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else

    // 消息接收者的父類
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
};

簡化objc_super結構體如下:


/**
 從`objc_msgSendSuper`函數的注釋可以看到結構體的兩個成員含義:the instance of the class that is to receive the message and the superclass at which to start searching for the method implementation.
 */
 
struct objc_super {
    // receiver就是消息接收者 (the instance of the class that is to receive the message)
    __unsafe_unretained _Nonnull id receiver;

    // super_class就是消息接收者的父類 (官方解釋:the superclass at which to start searching for the method implementation)
    __unsafe_unretained _Nonnull Class super_class;
};

通過objc_super底層定義,我們可以看到這個結構體也包含兩個成員

  • receiver
  • super_class

我們通過objc_msgSendSuper函數底層定義的注釋中可以查看到參數objc_super結構體中兩個成員的具體含義和作用

instance of the class that is to receive the message and the superclass at which to start searching for the method implementation

從上面注釋我們了解到receiver就是消息的接受者(也就是方法調用者),superclass就是指從父類開始查找方法

因此在Studentinit初始化函數中打印結果如下:

- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"%@", [self class]); // Student
        NSLog(@"%@", [self superclass]); // Person
        
        NSLog(@"%@", [super class]); // Student
        NSLog(@"%@", [super superclass]); // Person
    }
    return self;
}

classsuperclass函數的底層源碼實現:

- (Class)class {
    // self為方法調用者,也就是消息接收者(receiver),返回當前方法調用者的類對象
    return object_getClass(self);
}
- (Class)superclass {
    // self為方法調用者,也就是消息接收者(receiver),返回當前方法調用者的父類對象
    return return self->superclass;
}

講解示例Demo地址:https://github.com/guangqiang-liu/07.2-RunTimeSuper

更多文章

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。