动态添加类和已有类 重名?

简单回顾一下这部分知识点:对于已经存在的类我们用class_addProperty方法来添加属性,而对于动态创建的类我们通过class_addIvar添加属性, 它会改变一个已有类的内存布局,一般是通过objc_allocateClassPair动态创建一个class,才能调用class_addIvar创建Ivar,最后通过objc_registerClassPair注册class。Pair中文一对的意思,我只创建一个类,为什么这两个方法名会出现Pair这个词呢?这是因为创建类的时候也会创建元类。

// 动态创建类
-(void)creatClass {
    NSString *className = @"dynaminClass";
    if (!NSClassFromString(className)) {
        Class newClass = objc_allocateClassPair(NSString.class, className.UTF8String, 0);
        class_addMethod(newClass, @selector(test), (IMP)funcIMP, "v@:");
        objc_registerClassPair(newClass);
    }
}
// 生成类的实例
-(void)creatInstance {
    Class newClass = NSClassFromString(@"dynaminClass");
    id intanceOfClass = [[newClass alloc] init];
    // [intanceOfClass eat]; 编译不通过
    [intanceOfClass performSelector:@selector(func)];
}
// 调用方法
void funcIMP(Class self, SEL _cmd)
{
    Class class = [self class];
    // 类: dynaminClass, sel: test.
    NSLog(@"self: %@ sel: %s", class, _cmd);
}
复制代码

让咱们回到问题上,如果把创建类的if条件去掉,然后类名改为一个已有的类名,会发生什么呢? 大家肯定都知道,但是这里咱们先猜测一下:

1、不会crash,试想一下,一对双胞胎,外貌衣服都一样,我想要找某一个,那肯定不知道这两个哪个是。类比runtime,你给我创建了两个一样的类,就算能创建并注册成功,我应该找哪个呢?runtime表示我也很懵啊,会导致runtime混乱,产生出乎意料的问题。

2、会crash

尝试运行一下,不出意料,果然崩了,原因:EXC_BAD_ACCESS,这个问题相信很多人都头疼,别提了,我想静静?。咱们继续探索,runtime相信大家都了解,看一下继承链,实例->类>元类>根元类,其中只有实例能创建多个(地址不同),现在我动态注册了一个类,类名是已存在的类名,能创建成功并开辟内存吗?并不能,objc_allocateClassPair函数没crash的原因是内部返回直接return了,没走正常的逻辑,而且也不会崩溃,因为没有内存操作。而objc_registerClassPair注册操作会操作内存,崩溃位置在获取data函数(需要跑源码):

class_rw_t* data() const {
    return (class_rw_t *)(bits & FAST_DATA_MASK);
}
复制代码

因为类根本没在内存中,所以内存的操作肯定会报EXC_BAD_ACCESS(坏内存访问)。

总结:源码就不带大家看了,内部没什么特别的操作,讲这个的原因是我之前面试的时候碰到了。我在网上看面试题也没看到过这个问题,所以就当是为了面试的朋友们做个简单的解释吧。主要有两个考点:

1、动态创建类的时候只会创建一个类吗?不是的,还有对应的元类(源码中可以看到)

2、动态添加类和已有类重名会发生什么?crash,EXC_BAD_ACCESS(坏内存访问)。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享