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也是一样,只是它指向自己而已

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值