Objective-C runtime机制(10)——KVO的实现机制

使用KVO

自动触发KVO

在平日代码中,我们通过KVO来监视实例某个属性的变化。
比如,我们要监视Student 的 age属性,可以这么做:

@interface Student : NSObject
@property(nonatomic, strong) NSString *name;
@end

@interface ViewController ()

@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    Student *std = [Student new];
    std.name = @"Tom";
 	[std addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
 }

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
	...
}
@end

我们使用KVO需要遵循以下步骤:

  1. 调用addObserver:forKeyPath:options:context: 方法来注册观察者,观察者可以接收到KeyPath对应属性的修改通知
  2. 当观察的属性发生变化时,系统会在observeValueForKeyPath:ofObject:change:context:方法中回调观察者
  3. 当观察者不需要监听变化是,需要调用removeObserver:forKeyPath:KVO移除。需要注意的是,在观察者被释放前,必须要调用removeObserver:forKeyPath:将其移除,否则会crash。同时,作为被观察者,当其自身dealloc时,必须清空他的观察者,否则会crash。

手动触发KVO

当我们设置了观察者后,当被观察的keyPath对应的setter方法调用后,则会自动的触发KVO的回调函数。那么,有时候我们想要控制这种自动触发的机制,该怎么办呢?你可以重写如下方法:

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"balance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

automaticallyNotifiesObserversForKey方法声明在NSObject的Category NSObject(NSKeyValueObservingCustomization)中。

除了在setter方法中,有时候我们想主动触发一下KVO,该怎么办呢?
那就需要使用

willChangeValueForKey:
didChangeValueForKey:

来通知系统Key Value发生了改变。如:

- (void)updateName:(NSString *)name {
	[self willChangeVauleForKey:@"name"];
	_name = name;
	[self didChangeVauleForKey:@"name"];
}

KVO实现机制

那么,KVO背后是如何实现的呢?在苹果的官方文档上,有一个笼统的描述

Automatic key-value observing is implemented using a technique called
isa-swizzling.

The isa pointer, as the name suggests, points to the object’s class
which maintains a dispatch table. This dispatch table essentially
contains pointers to the methods the class implements, among other
data.

When an observer is registered for an attribute of an object the isa
pointer of the observed object is modified, pointing to an
intermediate class rather than at the true class. As a result the
value of the isa pointer does not necessarily reflect the actual class
of the instance.

You should never rely on the isa pointer to determine class
membership. Instead, you should use the class method to determine the
class of an object instance.

主要说了两件事:

  1. KVO是基于isa-swizzling技术实现的。isa-swizzling会将被观察对象的isa指针进行替换。
  2. 因为在实现KVO时,系统会替换掉被观察对象的isa指针,因此,不要使用isa指针来判断类的关系,而应该使用class方法。

为什么要替换掉isa指针

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回答: 在Objective-C中,可以使用mock类来模拟对象的行为和属性。通过使用KVO(键值观察)机制,您可以在不是自己创建的类中使用KVO,也可以只对您想要监听变化的类使用。被观察的对象必须继承自NSObject,并且使用Objective-C类型。被观察的变量必须声明为dynamic。这意味着您必须熟悉要观察的事务。\[1\] 关于Objective-C的mock类,可以参考苹果官方提供的《The Objective-C Programming Language》文档,该文档详细介绍了Objective-C的语法和特性。\[2\] 在Objective-C的类中,除了NSObject类之外,每个类都有一个isa值。super_class的值永远不会为nil,因为Objective-C中的其他类都以某种方式继承自NSObject。\[3\] #### 引用[.reference_title] - *1* *3* [Objective-C 运行时以及 Swift 的动态性](https://blog.csdn.net/weixin_42481708/article/details/117346110)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译)](https://blog.csdn.net/aiqian1239/article/details/102006188)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值