runtime
每个类里(每个OC对象里)都有一张表,左边SEL对应方法编号,右边对应IMP指针,方法实现
消息传递里 有一个桥梁 就像一个说明书 左边对应(SEL)对应的标题, 右边(IMP) 对应具体页码-->具体实现的函数
SEL: 方法编号
IMP: (是一个指针 指向一个函数,是一个函数的指针)方法实现,方法交换 实现交换的方法
例子:
Person.h
- (void)eat;
Person.m
// 底层实现 runtime 方法交换
+(Bool)resolveInstanceMethod:(SEL)sel
{
// 添加 EAT方法
clsss_addMethod(self,sel,eat,"");
return [super resolveInstanceMethod:sel];
}
void eat()
{
nslog("吃东西");
}
外部调用 [person eat];
总结:<>OC 的方法调用就是在调用C 的函数
// -------------------------
// 带参数的就不一样了
Person.h
- (void)eat:(NSString *)object;
Person.m
// 底层实现 runtime 方法交换 此方法证明每个类中是有SEL 和 IMP的
+(Bool)resolveInstanceMethod:(SEL)sel
{
// 添加 EAT方法
// sel本函数的sel
// eat 是下边void eat函数
clsss_addMethod(self,sel,eat,"");
return [super resolveInstanceMethod:sel];
}
如果直接加参数,传递过来的是p 对象,不能实现传参功能!!!!
所以
// OC方法调用会传递两个隐式参数
//因为OC方法调用就是消息发送
objc_msgSend(p,@selector(eat:),@"汉堡"); p->对应self @selector()->_cmd
// objc_msgSend() 和 void eat()相对应
void eat(id self,SEL _cmd, NSString *object)
{
nslog("吃东西:%@",object);
}
// 注意 OC的 方法调用其实就是 消息发送!!! 消息发送都会传递 两 隐式参数,self和_cmd(方法编号)
Person *p = [[Person alloc] init];
[p eat:@"汉堡"] --> 代码的 底层实现 就是
objc_msgSend(p,@selector(eat:),@"汉堡");
以 Person *p = [[Person alloc] init]; 例
底层 runtime 底层实现
大概实现
Person *p = ((id , SEL),(void *)objc_getClass("Person"),sel_registerName("alloc"),sel_registerName ("init"));
objc_getClass("Person") 通过 Person 找到 类
sel_registerName("alloc") 根据名字找到注册 alloc 方法
给底层分别发 alloc 和 init 消息,
总结 !!!!!
OC方法的本质 就是 SEL IMP
类里有 SEL 一一对应的 IMP (函数指针)
OC方法调用的时候
传递给这个函数的参数就是消息发送的参数
方法交换就是 SEL 和 IMP 对应关系调换
实际应用场景 是方法交换 (方法欺骗)根据方法欺骗 判空
数据的判空
https://blog.csdn.net/huxinguang_ios/article/details/69568757
rutime 还可以监听属性的变化 即 响应式编程 KVO
// ———————
runtime 方法交换
调用系统方法时,其实调用的是HK_URLWithString
KVO实现原理 响应式编程
// KVO监听属性变化 原理就是用runtime实现的
//实现原理分为几步
// 1. 动态创建Person子类
// 2. 改变P对象的类型(子类类型)
[_p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"监听到了");
}
//单独创建一个类 继承 Person
- (void)setName:(NSString *)name
{
//willChangeValueForKey didChangeValueForKey 就会触发外界的 addObserver
//触发的条件是 NSKeyValueObservingOptionNew 改变之前触发 willChangeValueForKey
//触发的条件是 NSKeyValueObservingOptionOld 改变之前触发 didChangeValueForKey
[self willChangeValueForKey:@"name"];
[super setName:name];
[self didChangeValueForKey:@"name"];
}
KVO实现原理
KVO利用runtime 动态床架 类的子类 然后利用 runtime 改变 属性真实数值
MVVM中 的路由跟这个类似
对应的网盘 视频名字 < 2018年2月28日--面试题-内存管理-rutime-KVO(一)>
移动硬盘名字 <Runtime-KVO>