类对象与元类对象的区别和联系
- 类对象存储的是实例方法列表,元类对象存储的是类方法列表
- 实例对象是objc_object结构,其中的isa指针指向其类对象,类对象是objc_class结构,objc_class是继承自objc_object结构,因此也有isa指针,其isa指针指向其元类对象,从而可以访问类方法
- 类对象和元类对象都是objc_class数据结构的
元类对象的isa指针都指向根元类对象,包括根元类对象自身
根元类对象的superclass指针,指向的是根类对象
根类对象的superclass指针,指向nil
当调用的类方法没有时,但是有同名的实例方法存在,那么会不会导致崩溃?
不会崩溃,当调用类方法时,会依次调用元类对象中的类方法列表,直至找到根元类对象的类方法列表,但是仍然没有找到时,会根据元类对象的superclass指针指向的根类对象的方法列表中去找同名的实例方法列表
消息传递流程
NS_ASSUME_NONNULL_BEGIN
@interface Mobile : NSObject
@end
NS_ASSUME_NONNULL_END
#import "Mobile.h"
@implementation Mobile
@end
#import "Mobile.h"
NS_ASSUME_NONNULL_BEGIN
@interface Phone : Mobile
@end
NS_ASSUME_NONNULL_END
#import "Phone.h"
@implementation Phone
- (instancetype)init {
self = [super init];
if (self) {
NSLog(@"%@",NSStringFromClass([self class])); //self isa指向类对象Phone ->NSObject类对象方法列表
NSLog(@"%@",NSStringFromClass([super class])); //super isa指向类对象
}
return self;
}
@end
-
[self class]
根据phone实例的isa指针,找到类对象,在类对象的缓存方法列表或实例方法列表中去寻找class
这个方法 - 本身是没有的,然后通过类对象中的superclass指针向其父类mobile中去寻找方法
- mobile类中也是没有的,顺次查到,直至知道根类对象NSObject,有该方法的实现,调用这个方法的实现,最终返回给接收者receiver,即phone实例对象,打印结果为:Phone
-
[super class]
会调用msgsendSuper这个函数,会从Phone类的父类对象方法列表中去查找,其中第一个固定参数是结构体objc_super
,该结构体中有一个id receiver
成员,接收者仍然是Phone的实例对象,因此最终打印结果也为:Phone
消息传递流程图.png
消息传递--缓存查找流程
- 通过给定的方法选择器SEL,作为key,通过hash算法,及通过一个hash函数cache_key_t来获取到对应的bucket_t结构在cache_t中的位置索引,从而获取到bucket_t,最终获取到bucket_t中的IMP函数指针
f(key) = key & mask
消息传递--当前类对象中的查找流程
- 在当前类对象的方法列表中,对于已排序好的列表,采用二分查找算法查找方法对应执行函数
- 对于没有排序好的列表,采用一般遍历查找方法对应执行函数
消息传递--父类逐级查找流程
- 通过当前类对象的superclass指针逐级向父类查找,判断父类是否为空,如果为空则结束
消息转发流程
-
对于实例方法的转发流程
消息转发流程.png
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RuntimeObject : NSObject
- (void)test;
@end
NS_ASSUME_NONNULL_END
#import "RuntimeObject.h"
@implementation RuntimeObject
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
return NO;
}else {
return [super resolveInstanceMethod:sel];
}
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(test)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}else {
return [super methodSignatureForSelector:aSelector];
}
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
}
@end