Runtime執行時
編譯時
和執行時
編譯時
顧名思義就是正在編譯的時候 . 那啥叫編譯呢?就是編譯器幫你把
原始碼翻譯成機器能識別的程式碼 .
執行時
就是程式碼跑起來了.被裝載到記憶體中去了 .
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
方法的底層實現
檢視c++
原始碼
建立一個類LKTeacher
,以及LKPerson
繼承自LKTeacher
,LKTeacher
新增例項方法teacherayHello
,LKPerson
新增例項方法personSayHello
和類方法classSayHello
js
int main(int argc, const char * argv[]) {
@autoreleasepool {
LKPerson *person = [LKPerson alloc];
[person personSayHello];
[person teacherayHello];
[LKPerson classSayHello];
}
return 0;
}
通過clang
將main.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`方式呼叫父類的方法,方法的本質還是訊息傳送。