1 runtime簡介
- RunTime簡稱運行時。OC就是運行時機制,也就是在運行時候的一些機制,其中最主要的是消息機制。
- 對于C語言,函數(shù)的調(diào)用在編譯的時候會決定調(diào)用哪個函數(shù)。
對于OC的函數(shù),屬于動態(tài)調(diào)用過程,在編譯的時候并不能決定真正調(diào)用哪個函數(shù),只有在真正運行的時候才會根據(jù)函數(shù)的名稱找到對應的函數(shù)來調(diào)用。 - 事實證明:
在編譯階段,OC可以調(diào)用任何函數(shù),即使這個函數(shù)并未實現(xiàn),只要聲明過就不會報錯。
在編譯階段,C語言調(diào)用未實現(xiàn)的函數(shù)就會報錯。
2 消息機制驗證
- 2.1 在xcode中創(chuàng)建一個Command Line(命令行)工程,在main.m文件中寫上以下兩句代碼:
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 創(chuàng)建并初始化一個object對象
NSObject *object= [NSObject alloc];
object = [object init];
}
return 0;
}
- 2.2 OC代碼轉(zhuǎn)換成C++格式
- cd /Users/Desktop/Clang 進入到main.m所在的文件夾
- clang -rewrite-objc main.m 執(zhí)行此命令,將oc轉(zhuǎn)化成C++
此時文件夾中多了一個main.cpp文件 - 打開main.cpp,發(fā)現(xiàn)main.m文件轉(zhuǎn)化成了10多萬行C++代碼,以下是被轉(zhuǎn)換后的main函數(shù)中的代碼:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSObject *object= ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
object = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)object, sel_registerName("init"));
}
return 0;
}
alloc對應的函數(shù) : objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
init對應的函數(shù): objc_msgSend(object, sel_registerName("init"));
// 第一個參數(shù):誰發(fā)送消息,類名
// 第二個參數(shù):發(fā)送一個什么樣的消息,方法名
3 objc_msgSend方法的使用
- 導入頭文件#import <objc/message.h>
- 取消objc_msgSend方法使用的限制
xcode6以后,蘋果不希望我們使用runtime,對objc_msgSend實行了注釋,如下:
OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
要想使用runtime方法,需要進行如下配置:
- 使用舉例
- 舉例1:
// OC寫法:
NSObject *objc = [NSObject alloc];
objc = [objc init];
// 純runtime寫法
NSObject *objc = objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
objc = objc_msgSend(objc, sel_registerName("init"));
// runtime與OC的混合寫法
NSObject *objc = objc_msgSend([NSObject class]), @selector(alloc));
objc = objc_msgSend(objc, @selector(init));
備注:
// 誰的事情誰開頭 -> 對象(objc)
// objc_getClass(<#const char *name#>):根據(jù)類名獲取類對象
// 類方法用類對象,對象方法用對象
- 舉例2:
(1)場景:創(chuàng)建一個person類,并實現(xiàn)兩個私有方法(沒有聲明的方法):
- (void)eat{
NSLog(@"吃東西");
}
- (void)run:(NSString *)name metre:(int)metre
{
NSLog(@"%@跑了%d米", name ,metre);
}
(2)實現(xiàn)過程代碼
// 分配內(nèi)存
Person *p = objc_msgSend([Person class], @selector(alloc));
// 初始化
p = objc_msgSend(p, @selector(init));
// 調(diào)用eat方法(沒有參數(shù))
objc_msgSend(p, @selector(eat));
// 調(diào)用run方法(有參數(shù))
objc_msgSend(p, @selector(run:metre:),@"小明", 100);
4 消息機制使用場景
- 1.封裝自己框架,盡量少的暴露接口,裝逼用
- 2.調(diào)用私有的方法,前提:知道已經(jīng)實現(xiàn),只是沒有聲明暴露出來