OC中Runtime super關(guān)鍵字

在平時(shí)的開發(fā)過程中敏晤,我們經(jīng)常會(huì)執(zhí)行[super xxx]來調(diào)用父類的方法遵岩,但是我們很少會(huì)去關(guān)心super關(guān)鍵字的底層是如何實(shí)現(xiàn)的集绰,接下來我們來看下super關(guān)鍵字底層實(shí)現(xiàn)原理菠劝,我們新建一個(gè)工程赛糟,然后創(chuàng)建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函數(shù):

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

接下來我們執(zhí)行命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 Student.mStudent.m文件轉(zhuǎn)換為底層c++文件版仔,轉(zhuǎn)換為底層的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方法進(jìn)行簡化如下:

- (void)run {
    [super run];
    
    /**
     結(jié)構(gòu)體objc_super包含兩個(gè)成員:
     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__);
}

我們發(fā)現(xiàn)當(dāng)我們在run函數(shù)中執(zhí)行[super run]后,最終底層轉(zhuǎn)換為objc_msgSendSuper()消息發(fā)送误墓,我們通過底層源碼看下objc_msgSendSuper函數(shù)的定義蛮粮,查找路徑objc4 -> message.h -> objc_msgSendSuper,具體底層函數(shù)定義如下:

/**
 * 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函數(shù)定義可以看到谜慌,函數(shù)接受兩個(gè)參數(shù)

  • objc_super
  • SEL

我們再來看下objc_super結(jié)構(gòu)體底層定義如下:

/// 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結(jié)構(gòu)體如下:


/**
 從`objc_msgSendSuper`函數(shù)的注釋可以看到結(jié)構(gòu)體的兩個(gè)成員含義: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底層定義然想,我們可以看到這個(gè)結(jié)構(gòu)體也包含兩個(gè)成員

  • receiver
  • super_class

我們通過objc_msgSendSuper函數(shù)底層定義的注釋中可以查看到參數(shù)objc_super結(jié)構(gòu)體中兩個(gè)成員的具體含義和作用

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

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

因此在Studentinit初始化函數(shù)中打印結(jié)果如下:

- (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函數(shù)的底層源碼實(shí)現(xiàn):

- (Class)class {
    // self為方法調(diào)用者欣范,也就是消息接收者(receiver)变泄,返回當(dāng)前方法調(diào)用者的類對象
    return object_getClass(self);
}
- (Class)superclass {
    // self為方法調(diào)用者,也就是消息接收者(receiver)恼琼,返回當(dāng)前方法調(diào)用者的父類對象
    return return self->superclass;
}

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

更多文章

  • ReactNative開源項(xiàng)目OneM(1200+star):https://github.com/guangqiang-liu/OneM:歡迎小伙伴們 star
  • iOS組件化開發(fā)實(shí)戰(zhàn)項(xiàng)目(500+star):https://github.com/guangqiang-liu/iOS-Component-Pro:歡迎小伙伴們 star
  • 簡書主頁:包含多篇iOS和RN開發(fā)相關(guān)的技術(shù)文章http://www.reibang.com/u/023338566ca5 歡迎小伙伴們:多多關(guān)注妨蛹,點(diǎn)贊
  • ReactNative QQ技術(shù)交流群(2000人):620792950 歡迎小伙伴進(jìn)群交流學(xué)習(xí)
  • iOS QQ技術(shù)交流群:678441305 歡迎小伙伴進(jìn)群交流學(xué)習(xí)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晴竞,隨后出現(xiàn)的幾起案子蛙卤,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颤难,死亡現(xiàn)場離奇詭異神年,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)行嗤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門已日,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人栅屏,你說我怎么就攤上這事飘千。” “怎么了既琴?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵占婉,是天一觀的道長泡嘴。 經(jīng)常有香客問我甫恩,道長,這世上最難降的妖魔是什么酌予? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任磺箕,我火速辦了婚禮,結(jié)果婚禮上抛虫,老公的妹妹穿的比我還像新娘松靡。我一直安慰自己,他們只是感情好建椰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布雕欺。 她就那樣靜靜地躺著,像睡著了一般棉姐。 火紅的嫁衣襯著肌膚如雪屠列。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天伞矩,我揣著相機(jī)與錄音笛洛,去河邊找鬼。 笑死乃坤,一個(gè)胖子當(dāng)著我的面吹牛苛让,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播湿诊,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼狱杰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厅须?” 一聲冷哼從身側(cè)響起仿畸,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎九杂,沒想到半個(gè)月后颁湖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宣蠕,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年甥捺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抢蚀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镰禾,死狀恐怖皿曲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吴侦,我是刑警寧澤屋休,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站备韧,受9級(jí)特大地震影響劫樟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜织堂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一叠艳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧易阳,春花似錦附较、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至事示,卻和暖如春早像,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背很魂。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工扎酷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遏匆。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓法挨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親幅聘。 傳聞我的和親對象是個(gè)殘疾皇子凡纳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355