runtime,运行时。
就是说程序运行的时候可以进行操作,如调用新函数、删除已有的函数、改变变量的值等。
runtime就是实现语言动态的api
1.类的动态改变
2.消息传递
一个类的内部定义如下
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class;//父类
const char *name;//类名
long version;//类的版本信息,默认为0
long info;//类信息,供运行期使用的一些位标识
long instance_size;//类的实例变量大小
struct objc_ivar_list *ivars;// 类的成员变量链表
struct objc_method_list **methodLists;// 方法链表
struct objc_cache *cache;//方法缓存
struct objc_protocol_list *protocols;//协议链表#
endif}
OBJC2_UNAVAILABLE;
isa和super_class
isa:
每个实例对象都有一个isa指针,指向对象的类;
类也是一个对象,所以也有isa指针,指向元类。
元类也是对象,它的isa指针指向根元类
一个类方法被调用的时候,元类会去查自己是否有实现,没有就查父类,直到根类。
给OC对象发消息,runtime库会根据这个对象的isa指针其父类,然后在类方法列表里面寻找实现,若没有,就根据super_class寻找父类方法列表,直到根类。找到就运行这个方法
isa:实例对象-》类-》元类-》直接到根元类(NSObject的元类),根元类的isa指向自己
superclass:类-》父类-》中间类-》根类NSObject,袁元-》父元类》中间元类-》根元类-》根类;NSObject的superclass指向nil
SEL:类成员方法的指针,SEL只是保存了方法编号,不是方法的地址。
IMP:保存方法的地址
Method:方法结构体,保存方法名、实现和类型描述字符串
1.动态添加方法
//调用方法
[model performSelector:@selector(Wenwen)];
//自己重写的方法
- (void)addFind{
NSLog(@"Wen Cheng");
}
//调用不存在的实例方法时调用
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if ([NSStringFromSelector(sel) isEqualToString:@"Wenwen"]) {
//这一行打断点
return YES;
}
return NO;
}
如果直接运行,肯定会报错的。因为我们还没有添加方法。所以在运行成功后,再断点处,使用lldb命令,进行添加:call class_addMethod(self, sel, class_getMethodImplementation([HeaderModel class], @selector(addFind)), “v@:*”);
,就可以看到打印的”Wen Cheng”
未找到方法实现时,会调用以下几个方法。
//调用不存在的类方法时调用,默认NO,加入处理再返回YES
+ (BOOL)resolveClassMethod:(SEL)sel;
//处理实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel;
//调用其它类的方法,返回有这个方法的target
- (id)forwardingTargetForSelector:(SEL)aSelector;
//将不存在的方法打包成NSInvocation传给你
- (void)forwardInvocation:(NSInvocation *)anInvocation;