對象和類以前已經分析過了,今天來分析一下方法,說到方法就不得不探究一下Runtime了~c++
Runtime
是一套API。api
詳細來講,是一套由c、c++、彙編
一塊兒編寫而成,併爲oc代碼提供運行時功能的api。markdown
爲何要這麼費勁巴拉的搞這麼一套東西,不直接用oc呢?app
運行時 & 編譯時iphone
運行時:代碼跑起來的時間,代碼會被裝載在內存ide
編譯時:正在編譯的時間,將源代碼翻譯成可識別的機器語言(如:二進制)函數
legacy version
, OC 1.0
,__OBJC__
,-old
modern version
, OC 2.0
,__OBJC2__
,-new
運行時動態庫 Runtime System Library
經過 編譯器 compiler
編譯以後,提供了 Framework&Service
和 Runtime API
供OC使用。post
咱們常常在OC中調用@selector()
,其實就是在和runtime打交道了
@selector()
NSSelectorFromName
sel_registerName
測試代碼:
// Person是繼承自NSObject 自定義的類
Person *person = [Person alloc];
[person sayHello];
//定義一個void fly() {···},直接調用方法
fly();
複製代碼
經過clang手段:
兼容編譯(代碼少):clang -rewrite-objc main.m -o main.cpp
完整編譯(不報錯):xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
複製代碼
看一下底層編譯成什麼:
Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("sayHello"));
fly();
複製代碼
解析:
((Person *(*)(id, SEL))(void *)objc_msgSend)
和 ((void (*)(id, SEL))(void *)objc_msgSend)
都是 類型強轉(id)objc_getClass("Person")
拿到Person類sel_registerName("alloc")
和 sel_registerName("sayHello")
都是 調用方法,比如@selector()
fly()
在clang
後,並無編譯成objc_msgSend
函數去調用。由於發送消息就是查找函數實現的過程,C函數能夠直接經過函數名(指針)找到,並不須要這一步。重點即:objc_msgSend(id,sel)
= 發送消息(消息接收者,方法編號)
由底層編譯能夠看出,咱們調用方法,在底層會變成objc_msgSend
函數的調用。也就是說:
方法的本質就是發送消息
!
假定條件: 有一個子類 Person,實例方法:run ,類方法:jump 有一個父類 People,實例方法:sayHi,類方法:sayBey
//person的角度
objc_msgSend(person, sel_registerName("run"));
複製代碼
//person的角度
objc_msgSend(objc_getClass("Person"), sel_registerName("jump"));
複製代碼
給父類發消息,要用另外一個函數
objc_msgSendSuper
,而且要用到objc_super
這個結構體
struct objc_super {
//只看oc2版本須要的2個參數
__unsafe_unretained _Nonnull id receiver;
//···
__unsafe_unretained _Nonnull Class super_class;
//···
};
複製代碼
//person 的角度
struct objc_super mySuper;
mySuper.receiver = person;
mySuper.super_class = [Person class];
objc_msgSendSuper(&mySuper, @selector(sayHi));
複製代碼
//person 的角度
struct objc_super myClassSuper;
myClassSuper.receiver = [Person class];
myClassSuper.super_class = class_getSuperclass(object_getClass([Person class]));// 元類
objc_msgSendSuper(&myClassSuper, sel_registerName("sayBey"));
複製代碼