博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS-动态创建类
阅读量:4135 次
发布时间:2019-05-25

本文共 3278 字,大约阅读时间需要 10 分钟。

在运行时动态创建一个类:

导入头文件#import <objc/runtime.h>,动态添加类,创建一个继承 NSString 的类NSStringSubClass类,如下代码:

// 类名也可以直接使用C字符串写法 ”NSStringSubClass“    NSString *className = @"NSStringSubClass";        // Creates a new class and metaclass.    Class newClass = objc_allocateClassPair(NSString.class, className.UTF8String, 0);        class_addMethod(newClass, @selector(eat), (IMP)EatFunction, "v@:");    objc_registerClassPair(newClass);

分析上述代码,以上述代码为例:

第一步:调用objc_allocateClassPair()函数,对类对(class and metaClass)进行分配内存,Pair的意思就是一对。三个参数,一是父类:NSString类;二是类名称:“NSStringSubClass”;三是额外字节:0。

小知识:C字符串和OC字符串互相转换:

const char *cStr = "哈哈";    NSString *str = @"嘻嘻";        NSString *cToStr = [NSString stringWithCString:cStr encoding:NSUTF8StringEncoding];    const char *strToC = str.UTF8String;

第二步:调用class_addMethod()函数,动态为类添加方法。四个参数,一是给哪个类添加方法:newClass类;二是方法名:eat;三是方法实现:EatFunction;四是类型:“v@:”,具体的意思查看,或者查看<runtime.h>文件第1791行处。

小知识:快捷键command+shift+o:查看方法所在类;command+shift+0:查看开发文档。

第三步:调用objc_registerClassPair() 注册该类,一个参数:newClass

添加的方法使用名为EatFunction实现的函数,其定义如下:

void EatFunction(id self, SEL _cmd){
NSLog(@"This object is %p.", self); NSLog(@"Class is %@, and super is %@.", [self class], [self superclass]); Class currentClass = [self class]; Class superClass = [self superclass]; for (int i = 0; i < 5; i++) {
NSLog(@"Following the isa classPointer:%p class:%@ superClassPointer:%p superClass:%@", currentClass, currentClass, superClass,superClass); currentClass = object_getClass(currentClass); superClass = class_getSuperclass(superClass); } NSLog(@"NSObject's class is %p", [NSObject class]); NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class])); // NSLog(@"NSObject's meta class is %p", objc_getMetaClass(NSStringFromClass([NSObject class]).UTF8String));}

在中我们说过,实例对象的本质是一个指向该对象真实类型的 isa 指针,即指向该实例对象的类,那么怎么获取该类呢?上例中的代码提到,通过函数object_getClass()可以获取到,该函数的参数是id(任意对象)类型。之前我们还说过,类也是对象,类的本质是objc_class结构类型的指针,在创建类的时候会生成一个isa指针,该指针指向metaClass(该类的元类),我们同样通过函数object_getClass()可以获取到该类的元类。有人会有疑问,这个函数的参数是id类型的对象啊,可以把类当作参数?答案是肯定的,因为类也是对象,当我们把Class类型当作参数时,获取就是该类的元类。口说无凭,我们来执行之前添加的EatFunction()函数,首先创建实例对象:

id intanceOfClass = [[newClass alloc] init];// [intanceOfClass eat]; 编译不通过[intanceOfClass performSelector:@selector(eat)];

由于没有声明eat方法,因此我使用performSelector:来调用它,避免编译器发出错误。

执行结果:

This object is 0x6000012045f0.Class is NSStringSubClass, and super is NSString.Following the isa classPointer:0x600001e43270  class:NSStringSubClass  superClassPointer:0x109fb44c8  superClass:NSStringFollowing the isa classPointer:0x600001e430f0  class:NSStringSubClass  superClassPointer:0x10a959ec8  superClass:NSObjectFollowing the isa classPointer:0x10a959e78  class:NSObject  superClassPointer:0x0  superClass:(null)Following the isa classPointer:0x10a959e78  class:NSObject  superClassPointer:0x0  superClass:(null)Following the isa classPointer:0x10a959e78  class:NSObject  superClassPointer:0x0  superClass:(null)NSObject's class is 0x10a959ec8NSObject's meta class is 0x10a959e78

分析结果:

intanceOfClass对象的地址:0x6000012045f0;
NSStringSubClass类的地址:0x600001e43270;
NSStringSubClass元类的地址:0x600001e43270;
NSStringSubClass元类的isa指针指向的元类地址:0x10a959e78,即指向NSObject类的元类;
NSObject类的元类指向的是它的元类自己;这也印证了我们上面所说,同时上篇文章中那幅isa指针和super_class指针的指向图也能印证。

转载地址:http://igivi.baihongyu.com/

你可能感兴趣的文章
P3258 [JLOI2014]松鼠的新家(树上点查分)
查看>>
Count on a tree SPOJ - COT(树上差分+lca+主席树)
查看>>
Diversity HDU - 6725
查看>>
Transformation HDU - 6726(百度之星复赛2019 dfs)
查看>>
Alyona and a tree CodeForces - 740D
查看>>
Drying POJ - 3104(二分+思维)
查看>>
River Hopscotch POJ - 3258(最小值最大化 二分)
查看>>
XKC's basketball team(2019徐州站网络赛E线段树)
查看>>
Queue CodeForces - 91B(线段树)
查看>>
so easy(2019徐州icpc网络赛B)
查看>>
Serge and Dining Room CodeForces - 1179C(线段树)
查看>>
Sequence II HDU - 5919(主席树)
查看>>
Problem E. Split The Tree HDU - 6504(主席树)
查看>>
[CQOI2009]叶子的染色(树形dp)
查看>>
[HAOI2015]树上染色(树形dp,树形背包)
查看>>
旅游(树形dp求树的最大独立集)
查看>>
[HNOI2003]消防局的设立(贪心)
查看>>
Light bulbs(上海icpc网络预选赛,差分离散化)
查看>>
Stone game(dp计数上海icpc网络预选赛)
查看>>
数糖纸(离散化)
查看>>