我们都知道一个类对象只能调用本类或者它的父类的类方法,其实一个类对象也能调用它的父类里面写的实例方法,下面为您揭开这里面的原理。
首先请看下面的OC对象中的三种类型的对象(实例对象、类对象、元类对象)之间的关系。下面就将围绕他们之间的关系讲述这里面的原理。如果您还对这张图有疑问的话,请移步本人撰写的OC对象调用方法原理
首先在文件中创建一个自定义类:
@interface Person : NSObject
+ (void)test;
@end
@implementation Person
@end
这个Person类的父类是NSObject类。
然后创建一个NSObject类的分类,并且声明一个test类方法,但是不实现它。在这个分类中撰写一个相同方法名的test的实例方法。
NSObject+Test.h文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Test)
+ (void)test;
@end
NS_ASSUME_NONNULL_END
NSObject+Test.m文件
#import "NSObject+Test.h"
@implementation NSObject (Test)
- (void)test
{
NSLog(@"-[NSObject test] - %p", self);
}
@end
在main.m文件中用Person类调用test方法:
[Person test];
最后在控制台的打印结果为:
-[NSObject test] - 0x1000011e0
说明子类的类对象成功调用了父类的实例方法。
它的原理为:
当Person类中没有实现test类方法,并且在NSObject类中也没有实现test类方法,但是在NSObject类中实现了test实例方法的时候,运行如下的代码,具体的调用流程为:系统根据Person类的class对象中的isa指针找到Person类的meta-class对象,在该meta-class对象中没有找到test类方法,然后系统再根据该meta-class对象中的superclass指针找到Person类的父类(NSObject类)的meta-class对象,系统在基类的meta-class对象中没有找到test类方法,然后系统再根据基类的meta-class对象中的superclass指针找到NSObject类的class对象,然后在NSObject类的class对象中找到了test实例方法,最后再进行调用,整个调用过程结束。
在main.m文件中的这句代码
[Person test];
其实可以写成
objc_msgSend([Person class], @selector(test));
的形式,从objc_msgSend可以看出,OC对象在调用方法的时候其实是不知道调用的是实例方法还是类方法的,只知道是给谁发消息,根据消息名一步一步地寻找,直到找到了为止。
”三人行,必有我师焉“, 欢迎各位批评指正。
如果您还觉得我写的不错的话请您点赞加关注,您的肯定是我前进的最大动力!
我是爱学习也爱您的树懒O(∩_∩)O