ios KVO 官方文档学习

从官方文档来武装一下自己(游击队->正规军)

原理说明

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.

  • 当对一个类添加观察后,这个类的 isa 指针被指向了一个中间类,而非真实的了类

关于 KVO 内部实现的原理,官方也就一句话带过

而这个中间类和 isa 就是 KVO 的核心了

为什么要实现一个中间类呢?

KVO的核心在于,属性的改变的时候,可以兼容的到

我们一般在更改属性值的时候一般都是

  1. 点方法 -> setter 方法
  2. setValueForKey
  3. 直接赋值

对于直接赋值,这个属于直接修改了指针的指向,这个就很难抓到了

所以重点看 setter 方法 和 setValueForKey 这两个方法

于是 KVO 就要在运行的时候动态的兼容我们的 setter 方法

那么苹果的实现方法就是,运行时新建了一个被观察的对象的子类

将被观察对象的 isa 指针指向子类

isa 略作说明

每个对象都有 isa 指针,isa 指针存储了一个类所有的信息。

例如:所有的方法、所有的属性

换句话来说,我们对 OC 类的操作,底层都是对 isa 指针的操作

例如: isKindOf 方法

其源码可以看出

对象 -> isa -> isa_class -> isa_super_class 直到找到 isa 类型相等

没有找到则 return false,找到则 return true

子类重写了 setter 方法,然后就可以抓到属性的改变了

至于怎么通知给观察者改变的,看下面的 官方文档重点翻译

官方文档重点翻译

  • OS X 中,model and controller layers 很大程度省依赖 KVO

if your objects inherit from NSObject and you create properties in the usual way, your objects and their properties will automatically be KVO Compliant. It is also possible to implement compliance manually

  • 继承自 NSObject 的类,常规的方式创建的属性,都自动的可以使用 KVO

Not all classes are KVO-compliant for all properties

  • 并不是所有的属性都兼容 KVO

Manual change notification provides additional control over when notifications are emitted, and requires additional coding. You can control automatic notifications for properties of your subclass by implementing the class method [automaticallyNotifiesObserversForKey:](https://developer.apple.com/documentation/objectivec/nsobject/1409370-automaticallynotifiesobservers).

  • 重写子类的 automaticallyNotifiesObserversForKey: 可以来控制属性的改变是否发送 KVO 通知
    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
 
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"balance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}
  • 触发 KVO
// Call the accessor method.
[account setName:@"Savings"];
 
// Use setValue:forKey:.
[account setValue:@"Savings" forKey:@"name"];
 
// Use a key path, where 'account' is a kvc-compliant property of 'document'.
[document setValue:@"Savings" forKeyPath:@"account.name"];
 
// Use mutableArrayValueForKey: to retrieve a relationship proxy object.
Transaction *newTransaction = <#Create a new transaction for the account#>;
NSMutableArray *transactions = [account mutableArrayValueForKey:@"transactions"];
[transactions addObject:newTransaction];
  • 重写 setter 方法 发送更改通知
- (void)setBalance:(double)theBalance {
    [self willChangeValueForKey:@"balance"];
    _balance = theBalance;
    [self didChangeValueForKey:@"balance"];
}
- (void)removeTransactionsAtIndexes:(NSIndexSet *)indexes {
    [self willChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"transactions"];
 
    // Remove the transaction objects at the specified indexes.
 
    [self didChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"transactions"];
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一“技”之长

Objective-C中通过下标的方式访问自定义数据模型中属性

      在Objective-C中,可以通过下标来访问数组中的元素,如果数组是NSMutableArray类型的可变数组,则还可以通过下标来对数组中的元素进...

7410
来自专栏小蠢驴iOS专题

实际开发中的深浅拷贝问题 - 解答

20640
来自专栏冰霜之地

iOS 如何实现Aspect Oriented Programming (上)

在“Runtime病院”住院的后两天,分析了一下AOP的实现原理。“出院”后,发现Aspect库还没有详细分析,于是就有了这篇文章,今天就来说说iOS 是如何实...

17320
来自专栏ShaoYL

iOS:KVO/KVC 的概述与使用

40680
来自专栏技术总结

iOS进阶之runtime作用

24190
来自专栏Rindew的iOS技术分享

iOS 禁用emoji系统中文键盘输入失效

22650
来自专栏陈满iOS

iOS开发·KVO用法,原理与底层实现: runtime模拟实现KVO监听机制(Blcok及Delgate方式)

KVO 是 Objective-C 对 观察者模式(Observer Pattern)的实现。当被观察对象的某个属性发生更改时,观察者对象会获得通知。有意思的是...

29930
来自专栏ShaoYL

ARC(Automatic Reference Counting )技术概述

405160
来自专栏哈雷彗星撞地球

iOS中的单例你用对了么?Objective-C中的单例Swift中的单例

单例模式怎么定义的,可能在不同的语言,不同的书中不完全一样,但是概况开来都应该是:一个类有且仅有一个实例,并且自行实例化向整个系统提供。 因此,首先你可能需要...

7730
来自专栏梧雨北辰的开发录

iOS运行时Runtime应用

18620

扫码关注云+社区

领取腾讯云代金券