iOS-动态创建类

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

导入头文件#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:NSString
Following the isa classPointer:0x600001e430f0  class:NSStringSubClass  superClassPointer:0x10a959ec8  superClass:NSObject
Following 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 0x10a959ec8
NSObject's meta class is 0x10a959e78

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值