4.动态运行时(RunTime)
- 基础数据结构
- 对象、类对象、元类对象是怎么理解的?以及他们之间的关系是怎样的(实例与类对象之间的关系以及类对象与元类对象之间的关系)?
- OC语言中的消息传递机制是怎样的?
- 缓存查找 (我们进行方法查找的过程当中,如何进行缓存的方法查找?会使用到系统或者说Runtime中一个方法缓存的机制,这个机制又是怎样运行的呢?)
- 消息转发流程是怎样的?
- Method-Swizzling(方法混写)是Runtime的一种运用(我们可以再运行时,去替换一些方法的实现,也得益于动态运行时这一个特性),可能会结合实际的场景,比如说通过时长统计框架这样的考察来了解对于Runtime的Methood-Swizzling技术的一个实际的运用
- 动态添加方法(Runtime提供的功能实现)
- 动态方法解析(Runtime提供的功能实现)
消息转发流程是怎样的?
- 对于实例方法,首先系统会调resolveInstanceMethod方法, resolveInstanceMethod是个类方法。
对于类方法的回调的是resolveClassMethod
resolveInstanceMethod的参数是方法选择器SEL,返回值为BOOL类型,
相当于告诉系统我们是否要解决当前实例方法的实现
如果返回的是YES,就是通知系统当前消息已处理,会结束这一消息转发流程
- 第二次:如果返回NO,系统会给我们第二次机会来处理这个消息。
然后会调用forwardingTargetForSelector方法,参数也是方法选择器SEL,返回值是id,
相当于告诉系统这个选择器这次实例方法的调用应该由哪个对象来处理,也就是转发对象是谁
若指定了转发目标,系统会把这个消息转发给转发目标,同时结束当前转发流程
- 若在第二次机会仍然没有转发目标,系统会给第三次处理这个消息的机会,也是最后一次机会
系统会调用methodSignatureForSelector方法,参数是SEL,
返回值是一个类methodSignature或者说是一个对象,是对于方法选择器的返回值类型以及参数个数和参数类型的封装,
此时如果返回了方法签名,系统会调用forwardInvocation,如果forwardInvocation能够处理这条消息,流程结束
如果methodSignatureForSelector返回为空或者forwardInvocation无法处理这条消息,被标记为消息无法处理,
就会crash,crash为未识别选择器
#import <Foundation/Foundation.h>
@interface RuntimeObject : NSObject
- (void)test;
@end
#import "RuntimeObject.h"
#import <objc/runtime.h>
@implementation RuntimeObject
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 如果是test方法 打印日志
if (sel == @selector(test)) {
NSLog(@"resolveInstanceMethod:");
return NO;
}
else{
// 返回父类的默认调用
return [super resolveInstanceMethod:sel];
}
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSLog(@"forwardingTargetForSelector:");
return nil;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
NSLog(@"methodSignatureForSelector:");
//如果当前进入的是test方法,返回一个正确的方法签名
// v 代表返回值是void类型的 @代表第一个参数类型时id,即self
// : 代表第二个参数是SEL类型的 即@selector(test)
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
else{
return [super methodSignatureForSelector:aSelector];
}
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"forwardInvocation:");
}
@end
RuntimeObject *obj = [[RuntimeObject alloc] init];
// 调用test方法,只有声明,没有实现,这样就能看到系统的一个转发流程是怎样的
[obj test];