KVO原理探究

一、初步探索

  1. 简单使用
    准备工作
@interface People : NSObject

@property(nonatomic, copy)NSString *name;
@property(nonatomic, copy)NSString *nickName;
@end
static void *PeopleNameContext = "PeopleName";
self.p = [People new];
    self.p.name = @"xiaobing";
    [self.p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:PeopleNameContext];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if (context == PeopleNameContext){
        NSLog(@"------%@",change);
    }
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    self.p.name = @"xiaobing11";
}

重点 此处 context 强烈建议写 这样的好处是可以更好的在观察回调中进行区分 代码更易读,执行效率上也会有提高

  1. 移除观察者
- (void)dealloc{
    [self.p  removeObserver:self forKeyPath:@"name"];
}

重点 强烈建议要移除观察者 例如当观察对象已经销毁 但是被观察者对象没有销毁 例如单利,这时会出现崩溃。

  1. 手动观察
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
    return YES;
}

默认情况下 automaticallyNotifiesObserversForKey 是返回YES 是开启自动观察的 当返回NO时就是手动观察 代码如下

- (void)setName:(NSString *)name{
    [self willChangeValueForKey:@"name"];
    _name = name;
    [self didChangeValueForKey:@"name"];
}
  1. 多值观察

添加属性
@property(nonatomic, assign)double downloadProgress;
@property(nonatomic, assign)double totalData;
@property(nonatomic, assign)double writeData;

+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
    NSSet *keyPath = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"downloadProgress"]){
        NSArray *affectingKeys = @[@"totalData",@"writeData"];
        keyPath = [keyPath setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPath;
}

downloadProgress 是依赖 totalData 和 writeData 的

  1. 可变数组
    @property(nonatomic, strong)NSMutableArray *dataArr;
    因为KVO是基于KVC的 [self.p.dataArr addObject:@“123”]; 这种没有引起set方法的调用 所以不会调用回调方法
[[self.p mutableArrayValueForKey:@"dataArr"] addObject:@"qwe"];

二、原理探究
KVO是通过生成一个中间类 以 NSKVONotifying 开头 改变被观察对象的isa指针 指向新类 NSKVONotifying_People 断点调试如下结果

  1. 在[self.p addObserver:self forKeyPath:@“name” options:NSKeyValueObservingOptionNew context:PeopleNameContext];处断点
  2. 断点前
    po object_getClassName(self.p)
    “People”
  3. 断点后
    po object_getClassName(self.p)
    “NSKVONotifying_People”
  4. 通过 po class_getSuperclass(NSClassFromString(@“NSKVONotifying_People”))
    结果是 People 得出新生成的类是原有类的子类
  5. 打印新生成类的子类
unsigned int count = 0;
    Method *methods = class_copyMethodList(NSClassFromString(@"NSKVONotifying_People"), &count);
    for (int i = 0; i < count; i ++){
        NSLog(@"----methods----%@", NSStringFromSelector(method_getName(methods[i])));
    }
    结果
    setDataArr:
setTotalData:
setWriteData:
setDownloadProgress:
 setName:
class
dealloc
_isKVOA

中间类重写了属性的set方法

  1. 生成的中间类是否销毁。不销毁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值