(看這遍文章之前,需要對Objective-C的Runtime有一定的了解)
在學習OC的runtime機制時候,有提到元類(meta class)這個概念。那什么是元類呢?
元類是類對象的類
聽起來很抽象,先看一段代碼
NSString *str = [[NSString alloc] int];
str是對象,NSString是OC的類,但是它也是對象(類對象)。
先看下OC的對象(Object)和類(Class)的結構體
對象的定義:
類的定義:
可以看出對象中isa是一個指向它的類的指針,細心的你會發現class里面同樣有一個isa指針,沒錯這個isa指向的是類的類,也就是所謂的元類(metaclass)。
那么為什么要有元類呢?從class的結構體可以看出,成員methodLists用來存放對象方法(也就是以“-”開始的方法),ivars用來存放屬性變量。那么,類方法(以"+"號開始的方法)還有靜態變量都要存放在哪里?沒錯,它們就是存放在元類的methodLists和ivars里面。
以下利用Runtime給NSString增加一個對象方法和一個類方法,這也算Runtime的運用。
1.用Runtime給NSString增加一個對象方法(相當于給NSString的類對象的方法列表增加一個方法)
SEL sel = sel_registerName("sayHello");
Class stringClass = objc_getClass(class_getName([NSString class])); //獲取類對象
class_addMethod(stringClass, sel, (IMP)sayHelloFunction, "v@:@");? //給stringClass的方法列表增加一個名稱叫sayHello的方法
id strInstance = [[NSString alloc] init]; //創建NSString的實例對象
((void(*)(id,SEL,id))objc_msgSend)(strInstance,sel,@"Hello World"); //調用對象方法
sayHelloFunction實現
void sayHelloFunction(id self, SEL _cmd,id content) {
NSLog(@"Runtime:%@",content);
}
輸出:
2.給NSString增加一個類方法(相當于給NSString的元類方法列表增加一個方法)
SEL sel = sel_registerName("sayHello");
Class metaClass = objc_getMetaClass(class_getName([NSString class])); //獲取NSString的元類
class_addMethod(metaClass, sel, (IMP)sayHelloFunction, "v@:@"); //給metaClass的方法列表增加一個名稱叫sayHello的方法
((void(*)(id,SEL,id))objc_msgSend)([NSString class],sel,@"Hello World");//調用NSString的類方法
sayHelloFunction實現
void sayHelloFunction(id self, SEL _cmd,id content) {
NSLog(@"Runtime metaclass:%@",content);
}
輸出:
最后再介紹下class_addMethod(Class cls, SEL name, IMP imp, const char *types)的參數
Class cls:需要增加方法的類
SEL name:增加的方法名稱
IMP imp:方法的實現
const char *types:用來指定新增方法的返回類型和參數列表
上面的例子中
class_addMethod(stringClass, sel, (IMP)sayHelloFunction, "v@:@")
void sayHelloFunction(id self, SEL _cmd,id content) {
NSLog(@"Runtime metaclass:%@",content);
}
對應方法的參數列表和返回類型,可以看出
"v@:@",
"v" ?: 代表返回為void類型
"@" : 代表id self
":" : 代表SEL
"@" : 代表 id content