#import "ViewController.h"
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self runtimeDemo];
}
void cMethod(id self, SEL _cmd, NSString *string){
NSLog(@"add C IMP 調(diào)用%@", string);
}
- (void)ocMethod:(NSString *)string{
NSLog(@"add OC IMP 調(diào)用%@", string);
}
@end
1、類 Class
- (void)runtimeDemo{
Class testClass = self.class;
//1、獲取類名 如果cls是Nil 返回空字符串
const char * className = class_getName(testClass);
NSLog(@"1、%s",className);
//2、獲取父類,如果cls是根類 or Nil 返回Nil.
Class superClass = class_getSuperclass(testClass);
NSLog(@"2、%@",superClass);
//在以后的文章中介紹元類
//3、獲取指定類的元類,返回元類名,如果runtime沒注冊則返回nil
Class metaClass = objc_getMetaClass(className);
NSLog(@"3、%@",metaClass);
//4、判斷是不是元類
BOOL isMeta = class_isMetaClass(metaClass);
NSLog(@"4、%d",isMeta);
}
控制臺
2017-11-09 16:54:55.754991+0800 runtime[8224:2271947] 1、ViewController
2017-11-09 16:54:55.755202+0800 runtime[8224:2271947] 2、UIViewController
2017-11-09 16:54:55.755321+0800 runtime[8224:2271947] 3、ViewController
2017-11-09 16:54:55.755433+0800 runtime[8224:2271947] 4、1
2、創(chuàng)建類,并且添加方法與變量
通過調(diào)用object_getClass(newClass),您可以獲得一個指向新元類的指針。要創(chuàng)建一個新類,首先調(diào)用objc_allocateClassPair。然后使用class_addMethod和class_addIvar等函數(shù)設(shè)置類的屬性。在構(gòu)建類時,調(diào)用objc_registerClassPair。新class現(xiàn)在可以使用了。實(shí)例方法和實(shí)例變量應(yīng)該添加到類本身。類方法應(yīng)該添加到元類。
(1)添加一個新類和元類
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
class_addMethod會重寫父類的實(shí)現(xiàn),但不會替換當(dāng)前類中已有的實(shí)現(xiàn)。要更改現(xiàn)有的實(shí)現(xiàn),請使用method_setImplementation。
/**
*superClass: 父類,傳Nil會創(chuàng)建一個新的根類
*name: 類名
*extraBytes: 0
*return:返回新類,創(chuàng)建失敗返回Nil,如果類名已經(jīng)存在,則創(chuàng)建失敗
*/
Class runTimeClass = objc_allocateClassPair([UIViewController class], "runTimeClass", 0);
/**
*添加成員變量
*這個函數(shù)只能在objc_allocateClassPair和objc_registerClassPair之前調(diào)用。不支持向現(xiàn)有類添加一個實(shí)例變量。
*這個類不能是元類。不支持在元類中添加一個實(shí)例變量。
*實(shí)例變量的最小對齊為1 << align。實(shí)例變量的最小對齊依賴于ivar的類型和機(jī)器架構(gòu)。對于任何指針類型的變量,請通過log2(sizeof(pointer_type))。
*/
BOOL isAddSuccess1 = class_addIvar(runTimeClass, "_name", sizeof(NSString*), log2(sizeof(NSString*)), @encode(NSString*));
BOOL isAddSuccess2 = class_addIvar(runTimeClass, "_dataArr", sizeof(NSMutableArray*), log2(sizeof(NSMutableArray*)), @encode(NSMutableArray*));
//添加對象方法
//types 一組字符,用來描述方法的參數(shù)的類型。由于函數(shù)必須至少使用兩個arguments - self和_cmd,因此第二個和第三個字符必須是 “@:” (第一個字符是返回類型)。
class_addMethod(runTimeClass, NSSelectorFromString(@"dynamicCMethod"), (IMP)cMethod, "v@:@");
//獲取oc方法的指針
IMP ocIMP = class_getMethodImplementation_stret([self class], @selector(ocMethod:));
//動態(tài)添加一個oc方法的實(shí)現(xiàn)
class_addMethod(runTimeClass, NSSelectorFromString(@"dynamicOCMethod"),ocIMP , "v@:@");
objc_registerClassPair(runTimeClass);
//添加一個類方法
//獲取runTimeClass的元類
Class metaClass = objc_getMetaClass(class_getName(runTimeClass));
class_addMethod(metaClass, NSSelectorFromString(@"dynamicClassMethod"), ocIMP, "v@:@");
//copy成員變量列表
//返回Ivar指針類型的數(shù)組
unsigned int count = 0;
Ivar * varList = class_copyIvarList(runTimeClass, &count);
// 遍歷成員變量列表,其中每個變量都是Ivar類型的結(jié)構(gòu)體
//const Ivar *p = varList 初始化一個指針,指向數(shù)組的地址
for (const Ivar *p = varList; p < varList + count; p++)
{
//用ivar接收指針p指向的地址 存儲的內(nèi)容
Ivar const ivar = *p;
NSLog(@"查看成員變量 ivar: %@", [NSString stringWithUTF8String:ivar_getName(ivar)]);
}
// 用完之后釋放內(nèi)存
free(varList);
//使用動態(tài)創(chuàng)建的類,變量與方法
id test = [[runTimeClass alloc] init];
//給_dataArr賦值
[test setValue:@[@1,@2] forKey:@"_dataArr"];
NSLog(@"_dataArr的值\n%@",[test valueForKey:@"_dataArr"]);
//調(diào)用動態(tài)添加的方法
[test performSelector:NSSelectorFromString(@"dynamicCMethod") withObject:@"動態(tài)添加的C方法" afterDelay:0];
[test performSelector:NSSelectorFromString(@"dynamicOCMethod") withObject:@"動態(tài)添加的OC方法" afterDelay:0];
//調(diào)用類方法
//注意要使用類進(jìn)行調(diào)用
[runTimeClass performSelector:NSSelectorFromString(@"dynamicClassMethod") withObject:@"動態(tài)添加的類方法" afterDelay:0];
2017-11-13 20:57:54.578454+0800 runtime[48091:4961752] 查看成員變量 ivar: _name
2017-11-13 20:57:54.578614+0800 runtime[48091:4961752] 查看成員變量 ivar: _dataArr
2017-11-13 20:57:54.578972+0800 runtime[48091:4961752] _dataArr的值
(
1,
2
)
2017-11-13 20:57:54.586745+0800 runtime[48091:4961752] add C IMP 調(diào)用動態(tài)添加的C方法
2017-11-13 20:57:58.478024+0800 runtime[48091:4961752] add OC IMP 調(diào)用動態(tài)添加的OC方法
2017-11-13 20:57:58.478409+0800 runtime[48091:4961752] add OC IMP 調(diào)用動態(tài)添加的類方法
(2)銷毀類以及關(guān)聯(lián)的元類
被銷毀的類類必須是使用objc_allocateClassPair來分配的。
【注意】如果cls類或任何子類的實(shí)例存在,則不要調(diào)用此函數(shù)。
//先銷毀cls的對象
test = nil;
objc_disposeClassPair(runTimeClass);