Runtime運行時

語言: CN / TW / HK

編譯時運行時

編譯時 顧名思義就是正在編譯的時候 . 那啥叫編譯呢?就是編譯器幫你把 源代碼翻譯成機器能識別的代碼 .
運行時 就是代碼跑起來了.被裝載到內存中去了 .

Runtime版本

Runtime有兩個版本 一個Legacy版本(早期版本) ,一個Modern版本(現行版本) * 早期版本對應的編程接口:Objective-C 1.0 * 現行版本對應的編程接口:Objective-C 2.0 * 早期版本用於Objective-C 1.0, 32位的Mac OS X的平台上 * 現行版本:iPhone程序和Mac OS X v10.5 及以後的系統中的 64 位程序

Runtime調用三種方式

1.Objective-C Code方式,例如[person sayHello]
2.Framework&Serivce 方式,例如isKindofClass
3.Runtime API方式,例如class_getInstanceSize

image.png

方法的底層實現

查看c++源碼

創建一個類LKTeacher,以及LKPerson繼承自LKTeacherLKTeacher添加實例方法teacherayHelloLKPerson添加實例方法personSayHello和類方法classSayHello js int main(int argc, const char * argv[]) { @autoreleasepool { LKPerson *person = [LKPerson alloc]; [person personSayHello]; [person teacherayHello]; [LKPerson classSayHello]; } return 0; } 通過clangmain.m文件編譯成main.cpp文件 js clang -rewrite-objc main.m -o main.cpp 查看main.cpp文件

```js static void _I_LKTeacher_teacherSayHello(LKTeacher * self, SEL _cmd) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_07_zf2hbch50bn79j6p806fy1t80000gn_T_main_0a11ef_mi_0); }

static void _I_LKPerson_personSayHello(LKPerson * self, SEL _cmd) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_07_zf2hbch50bn79j6p806fy1t80000gn_T_main_64ea0d_mi_1); }

static void _C_LKPerson_classSayHello(Class self, SEL _cmd) { NSLog((NSString *)&__NSConstantStringImpl__var_folders_07_zf2hbch50bn79j6p806fy1t80000gn_T_main_64ea0d_mi_2); }

int main(int argc, const char * argv[]) { / @autoreleasepool / { __AtAutoreleasePool __autoreleasepool; LKPerson person = ((LKPerson ()(id, SEL))(void )objc_msgSend)((id)objc_getClass("LKPerson"), sel_registerName("alloc")); ((void ()(id, SEL))(void )objc_msgSend)((id)person, sel_registerName("personSayHello")); ((void ()(id, SEL))(void )objc_msgSend)((id)person, sel_registerName("teacherSayHello")); ((void ()(id, SEL))(void )objc_msgSend)((id)objc_getClass("LKPerson"), sel_registerName("classSayHello")); } return 0; } `` 可以看到,方法的實現都是通過objc_msgSend方式實現,既然如此,我們是否可以直接通過objc_msgSend`發送消息來調用方法了。

js objc_msgSend((id)person, sel_registerName("personSayHello"));

必須導入相應的頭文件#import
關閉objc_msgSend檢查機制:target --> Build Setting -->搜索objc_msgSend -- Enable strict checking of obc_msgSend calls設置為NO

通過objc_msgSend[person personSayHello]結果是一樣的。
總結:方法的本質就是消息發送

父類方法的調用

上面可以看出,[person teacherayHello]可以直接調用到父類的方法。那麼父類方法的調用又是怎麼樣的流程了。
LKPerson.m文件轉換為LKPerson.cpp文件

js ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("LKPerson"))}, sel_registerName("teacherSayHello")); 可以看到[super teacherayHello]是通過objc_msgSendSuper實現的。可以看出objc_msgSendSuper的參數objc_super ```js 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_msgSendSuper`方式調用父類的方法,方法的本質還是消息發送。

「其他文章」