iOS 类和元类的关系

事情的始末是这样的,同学想验证一下resolveClassMethod是否执行(resolveClassMethod是一个对象调用一个不存在类方法时,会执行此方法,不懂的要恶补一下了,可以看我这篇文章:Objective-C消息转发),然后发来了如下代码:

[NSObject performSelector:@selector(hehe)];

当时看完之后产生了疑惑,performSelector是一个实例方法,NSObject是一个类,难道编译不会报错吗?后来亲测发现确实不会报错。

然后开始了我们今天的故事:
我们都知道下面这样写一定会出错

@interface TestObject : NSObject
@end
@implementation TestObject
- (void)method1{
       [TestObject method2];//这样调用一定会编译错误
}
- (void)method2{}

然而这样写却不会报错

@interface TestObject : NSObject
@end
@implementation TestObject
- (void)method{
   [NSObject performSelector:@selector(hehe)];
}

甚至于这样写也不会报错
创建一个NSObject的类目

@interface NSObject (hehe)
+(void)run;
@end
@implementation NSObject (hehe)
-(void)run{
    NSLog(@"run.....");
}
@end

然后调用

[NSObject run];

这是为什么哪?

看一张关系图

图片.png

(此图来源自网络)
假设A类继承自B类,B类继承自NSObject
A便是途中的Subclass(class),B便是图中的Superclass(class),NSObject便是Root class(class);
A *a = [A new];
其实A和a一样,也是对象,A称为类对象,a称为实例对象
每一个类对象都有一个isa指针

 Class isa  OBJC_ISA_AVAILABILITY;

这个isa指针的指向就是该类对象的元类,每一个类都是它的元类的对象,元类是对类对象的描述,就像类是普通实例对象的描述一样。

每一个类里面声明的类方法,其本质就是把该类方法放到元类的方法列表上面,所以类在调用类方法时,可以想象成是元类的对象在调用一个实例方法。

A的父类是B,A的元类的父类是B元类的父类,B的父类是NSObject,NSObject的父类是nil,B元类的父类是NSObject的元类;特别注意的一点,NSObject的元类的父类是NSObject,NSObject的isa指针又指向NSObject的元类,所以在NSObject里面的所有方法,NSObject的元类也都拥有,1、所以用NSObject 调用任意NSObject里面的实例方法都是可以成功的,2、这也就解释了上面的声明里面是+(void)run;类方法,实现里面是-(void)run{ NSLog(@"run.....");}实例方法,调用却不会崩溃。

类和元类是一个闭环,实例指向类,类指向元类,元类指向跟元类,跟元类指向自身,根元类的父类是NSObject

元类是 Class 对象的类。每个类(Class)都有自己独一无二的元类(每个类都有自己第一无二的方法列表)。这意味着所有的类对象都不同。

NSObject里面的所有实力方法,任意类都可以通过类方法调用。

所有的meta-class使用基类的meta-class作为自己的基类,对于顶层基类的meta-class也是一样,只是它指向自己而已

猜你喜欢

转载自blog.csdn.net/wangletiancsdn/article/details/104260373