iOS底层学习-day-4

前言-OC语法篇

我是一名iOS开发者, iOS底层 菜鸟的进阶之路30天。

问题

iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)

  • 利用RuntimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
  • 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
  • willChangeValueForKey:
  • 父类原来的setter
  • didChangeValueForKey:
  • 内部会触发监听器(Oberser)的监听方法(observeValueForKeyPath:ofObject:change:context:)

如何手动触发KVO? 问题没意义

  • 手动调用willChangeValueForKey:和didChangeValueForKey:

直接修改成员变量会触发KVO么?

  • 不会触发KVO

KVO本质(KVO的效率比代理的效率低)

使用了KVO与没有使用KVO对象的区别
  • KVO动态生成的子类和person的方法实现地址的区别
    在这里插入图片描述
// NSKVONotifying_MJPerson是使用Runtime动态创建的一个类,是MJPerson的子类,而且NSKVONotifying_MJPerson子类superclass指向父类MJPerson
// self.person1.isa => NSKVONotifying_MJPerson
[self.person1 setAge:21];//使用了KVO监听
// self.person2.isa => MJPerson
[self.person2 setAge:22];
  • 窥探person的KVO的方法
NSKVONotifying_MJPerson中的 setAge方法
- (void)setAge:(int)age {
    _NSSetIntValueAndNotify();
}

// 伪代码
void _NSSetIntValueAndNotify() {
    [self willChangeValueForKey:@"age"];
    [super setAge:age];
    [self didChangeValueForKey:@"age"];
}

- (void)didChangeValueForKey:(NSString *)key {
    // 通知监听器,某某属性值发生了改变
    [oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
打印出setAge方法@implementation具体实现在哪里
[self.person1 methodForSelector:@selector(setAge:)]
p (IMP)0x1065687c0//lldb中直接输入类_person1的(IMP)
KVO的内部实现-NSKVONotifying_MJPerson
  • KVO内部方法实现
    在这里插入图片描述
- (Class)class {
    return [MJPerson class];
}

- (void)dealloc {
    // 收尾工作
}

- (BOOL)_isKVOA {
    return YES;
}

方法的遍历

- (void)printMethodNamesOfClass:(Class)cls {
    unsigned int count;
    // 获得方法数组
    Method *methodList = class_copyMethodList(cls, &count);
    
    // 存储方法名
    NSMutableString *methodNames = [NSMutableString string];
    
    // 遍历所有的方法
    for (int i = 0; i < count; i++) {
        // 获得方法
        Method method = methodList[i];
        // 获得方法名
        NSString *methodName = NSStringFromSelector(method_getName(method));
        // 拼接方法名
        [methodNames appendString:methodName];
        [methodNames appendString:@", "];
    }
    
    // 释放
    free(methodList);
    
    // 打印方法名
    NSLog(@"%@ %@", cls, methodNames);
}

发布了12 篇原创文章 · 获赞 0 · 访问量 118

猜你喜欢

转载自blog.csdn.net/weixin_41732253/article/details/103715855