Runtime讲解实际应用和KVO实现原理响应式编程/OC方法本质SEL/IMP

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>

猜你喜欢

转载自blog.csdn.net/qq_29680975/article/details/80676846